English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
Scikit-learn kütüphanesinin sınıflandırma modelleri ve bunların ONNX'e aktarılması

Scikit-learn kütüphanesinin sınıflandırma modelleri ve bunların ONNX'e aktarılması

MetaTrader 5Örnekler | 12 Ağustos 2024, 12:08
122 0
MetaQuotes
MetaQuotes

Teknolojinin gelişmesi, veri işleme algoritmaları oluşturmaya yönelik temelde yeni bir yaklaşımın ortaya çıkmasına neden olmuştur. Önceden, her bir özel görevi çözmek için, ilgili algoritmaların açık bir şekilde biçimlendirilmesi ve geliştirilmesi gerekiyordu.

Makine öğreniminde bilgisayar, verileri işlemenin en iyi yollarını kendi kendine bulmayı öğrenir. Makine öğrenimi modelleri, sınıflandırma görevlerini (sabit bir sınıf kümesinin olduğu ve amacın her bir sınıfa ait belirli bir özellik kümesinin olasılıklarını bulmak olduğu) ve regresyon görevlerini (amacın belirli bir özellik kümesine dayalı olarak hedef değişkenin sayısal değerini hesaplamak olduğu) başarıyla çözebilir. Bu temel bileşenlere dayanarak daha karmaşık veri işleme modelleri oluşturulabilir.

Scikit-learn kütüphanesi hem sınıflandırma hem de regresyon için çok sayıda araç sağlar. Belirli yöntemlerin ve modellerin seçimi verilerin karakteristiğine bağlıdır, çünkü farklı yöntemler göreve bağlı olarak değişen etkinliğe sahip olabilir ve farklı sonuçlar sağlayabilir.

ONNX Runtime is now open source” başlıklı basın bülteninde, ONNX Runtime'ın ONNX-ML profilini de desteklediği belirtilmektedir:

ONNX Runtime is the first publicly available inference engine with full support for ONNX 1.2 and higher including the ONNX-ML profile.

ONNX-ML profili, ONNX'in makine öğrenimi (ML) modelleri için özel olarak tasarlanmış bir parçasıdır. Sınıflandırma, regresyon, kümeleme vb. gibi çeşitli ML model türlerini, ONNX'i destekleyen çeşitli platformlarda ve ortamlarda kullanılabilecek uygun bir biçimde tanımlamak ve temsil etmek için tasarlanmıştır. ONNX-ML profili, makine öğrenimi modellerinin iletimini, dağıtımını ve yürütülmesini basitleştirerek onları daha erişilebilir ve taşınabilir hale getirir.

Bu makalede, Fisher'ın iris sınıflandırma görevini çözmek için Scikit-learn paketindeki tüm sınıflandırma modellerinin uygulanmasını inceleyeceğiz. Ayrıca bu modelleri ONNX formatına dönüştürmeye ve elde edilen modelleri MQL5 programlarında kullanmaya çalışacağız.

Ek olarak, orijinal modellerin doğruluğunu tam iris veri setindeki ONNX versiyonlarıyla karşılaştıracağız.


İçindekiler



1. Fisher'ın iris veri kümesi

İris veri kümesi, makine öğrenimi alanında en iyi bilinen ve en yaygın kullanılan veri kümelerinden biridir. İlk olarak 1936 yılında istatistikçi ve biyolog R.A. Fisher tarafından tanıtılmış ve o zamandan beri sınıflandırma görevleri için klasik bir veri kümesi haline gelmiştir.

İris veri kümesi, üç iris çiçeği türünün (Iris setosa, Iris virginica ve Iris versicolor) çanak ve taç yapraklarının ölçümlerinden oluşur.

Iris setosa

Şekil 1. Iris setosa


Şekil 2. Iris virginica

Şekil 2. Iris virginica


Şekil 3. Iris versicolor

Şekil 3. Iris versicolor


İris veri kümesi, her üç türden 50'şer örnek olmak üzere 150 iris çiçeği örneğinden oluşmaktadır. Her örnek dört sayısal özelliğe sahiptir (santimetre cinsinden ölçülür):

  1. Çanak yaprak uzunluğu (sepal length)
  2. Çanak yaprak genişliği (sepal width)
  3. Taç yaprak uzunluğu (petal length)
  4. Taç yaprak genişliği (petal width)

Her örnek ayrıca iris çiçeği türünü (Iris setosa, Iris virginica veya Iris versicolor) belirten ilgili bir sınıfa sahiptir. Bu sınıflandırma özelliği, iris veri kümesini sınıflandırma ve kümeleme gibi makine öğrenimi görevleri için ideal bir veri kümesi haline getirmektedir.

MetaEditor Python komut dosyalarıyla çalışmaya olanak tanır. Bir Python komut dosyası oluşturmak için MetaEditor'da "Dosya" menüsünden "Yeni"ye tıklayın ve böylece oluşturulacak nesneyi seçmek için bir iletişim kutusu görünecektir (bkz. Şekil 4).

Şekil 4. MQL5 Sihirbazında Python komut dosyası oluşturma - Adım 1

Şekil 4. MQL5 Sihirbazında Python komut dosyası oluşturma - Adım 1

Ardından, komut dosyası için bir ad girin, örneğin "IRIS.py" (bkz. Şekil 5).

Şekil 5. MQL5 Sihirbazında Python komut dosyası oluşturma - Adım 2 - Komut dosyası adı

Şekil 5. MQL5 Sihirbazında Python komut dosyası oluşturma - Adım 2 - Komut dosyası adı

Devamında, hangi kütüphanelerin kullanılacağını belirtebilirsiniz. Bizim durumumuzda, bu alanları boş bırakacağız (bkz. Şekil 6).

Şekil 6. MQL5 Sihirbazında Python komut dosyası oluşturma - Adım 3

Şekil 6. MQL5 Sihirbazında Python komut dosyası oluşturma - Adım 3


İris veri setini analiz etmeye başlamanın bir yolu da verileri görselleştirmektir. Grafiksel bir gösterim, verilerin yapısını ve özellikler arasındaki ilişkileri daha iyi anlamamızı sağlar.

Örneğin, farklı iris çiçeği türlerinin özellik uzayında nasıl dağıldığını görmek için bir dağılım grafiği oluşturabilirsiniz.

Python komut dosyası kodu:

# The script shows the scatter plot of the Iris dataset features
# Copyright 2023, MetaQuotes Ltd.
# https://mql5.com

import matplotlib.pyplot as plt
from sklearn import datasets

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# extract sepal length and sepal width (the first two features)
sepal_length = X[:, 0]
sepal_width = X[:, 1]

# create a scatter plot
plt.figure(figsize=(8, 6))
plt.scatter(sepal_length, sepal_width, c=y, cmap=plt.cm.Set1, edgecolor='k')
plt.xlabel('Sepal Length (cm)')
plt.ylabel('Sepal Width (cm)')
plt.title('Scatter Plot for Sepal Length and Sepal Width')
plt.colorbar(label='Iris Species', ticks=[0, 1, 2])
plt.show()

# save the scatter plot to a file (optional)
# plt.savefig('scatter_plot_sepal_length_width.png')

# Extract petal length and petal width (the third and fourth features)
petal_length = X[:, 2]
petal_width = X[:, 3]

# create a scatter plot
plt.figure(figsize=(8, 6))
plt.scatter(petal_length, petal_width, c=y, cmap=plt.cm.Set1, edgecolor='k')
plt.xlabel('Petal Length (cm)')
plt.ylabel('Petal Width (cm)')
plt.title('Scatter Plot for Petal Length and Petal Width')
plt.colorbar(label='Iris Species', ticks=[0, 1, 2])
plt.show()

# save the scatter plot to a file (optional)
# plt.savefig('scatter_plot_petal_length_width.png')

Bu kodu çalıştırmak için MetaEditor'a kopyalamanız (bkz. Şekil 7) ve "Derle"ye tıklamanız gerekir.

Şekil 7. MetaEditor'da IRIS.py komut dosyası

Şekil 7. MetaEditor'da IRIS.py komut dosyası


Sonrasında, grafikler ekranda görünecektir:

Şekil 8. Çanak yaprak uzunluğu/çanak yaprak genişliği grafiği ile MetaEditor'da IRIS.py komut dosyası

Şekil 8. Çanak yaprak uzunluğu/çanak yaprak genişliği grafiği ile MetaEditor'da IRIS.py komut dosyası


Şekil 9. Taç yaprak uzunluğu/taç yaprak genişliği grafiği ile MetaEditor'da IRIS.py komut dosyası

Şekil 9. Şekil 9. Taç yaprak uzunluğu/taç yaprak genişliği grafiği ile MetaEditor'da IRIS.py komut dosyası


Onlara daha yakından bakalım.

Şekil 10. Çanak yaprak uzunluğu/çanak yaprak genişliği dağılım grafiği

Şekil 10. Çanak yaprak uzunluğu/çanak yaprak genişliği dağılım grafiği


Bu grafikte, farklı iris çiçeği türlerinin çanak yaprak uzunluğu ve çanak yaprak genişliğine göre nasıl dağıldığını görüyoruz. Iris setosa'nın diğer iki türe kıyasla tipik olarak daha kısa ve daha geniş çanak yapraklara sahip olduğunu gözlemliyoruz.

Şekil 11. Taç yaprak uzunluğu/taç yaprak genişliği dağılım grafiği

Şekil 11. Taç yaprak uzunluğu/taç yaprak genişliği dağılım grafiği



Bu grafikte, farklı iris çiçeği türlerinin taç yaprak uzunluğu ve taç yaprak genişliğine göre nasıl dağıldığını görüyoruz. Iris setosa'nın en kısa ve en dar taç yapraklara, Iris virginica'nın en uzun ve en geniş taç yapraklara sahip olduğunu ve Iris versicolor'un bu ikisinin arasında kaldığını gözlemliyoruz.

İris veri kümesi, makine öğrenimi modellerini eğitmek ve test etmek için ideal bir veri kümesidir. Bunu, bir sınıflandırma görevi için makine öğrenimi modellerinin etkinliğini analiz etmek için kullanacağız.



2. Sınıflandırma için modeller

Sınıflandırma, makine öğrenimindeki temel görevlerden biridir ve amacı, verileri belirli özelliklere göre farklı kategorilere veya sınıflara ayırmaktır.

Şimdi scikit-learn paketindeki ana makine öğrenimi modellerini inceleyelim.


Scikit-learn sınıflandırıcılarının listesi

Scikit-learn'deki mevcut sınıflandırıcıların listesini görüntülemek için aşağıdaki kodu kullanabilirsiniz:

# ScikitLearnClassifiers.py
# The script lists all the classification algorithms available in scikit-learn
# Copyright 2023, MetaQuotes Ltd.
# https://mql5.com

# print Python version
from platform import python_version  
print("The Python version is ", python_version()) 

# print scikit-learn version
import sklearn
print('The scikit-learn version is {}.'.format(sklearn.__version__))

# print scikit-learn classifiers
from sklearn.utils import all_estimators
classifiers = all_estimators(type_filter='classifier')
for index, (name, ClassifierClass) in enumerate(classifiers, start=1):
    print(f"Classifier {index}: {name}")

Çıktı:

Python    The Python version is  3.10.0
Python    The scikit-learn version is 1.2.2.
Python    Classifier 1: AdaBoostClassifier
Python    Classifier 2: BaggingClassifier
Python    Classifier 3: BernoulliNB
Python    Classifier 4: CalibratedClassifierCV
Python    Classifier 5: CategoricalNB
Python    Classifier 6: ClassifierChain
Python    Classifier 7: ComplementNB
Python    Classifier 8: DecisionTreeClassifier
Python    Classifier 9: DummyClassifier
Python    Classifier 10: ExtraTreeClassifier
Python    Classifier 11: ExtraTreesClassifier
Python    Classifier 12: GaussianNB
Python    Classifier 13: GaussianProcessClassifier
Python    Classifier 14: GradientBoostingClassifier
Python    Classifier 15: HistGradientBoostingClassifier
Python    Classifier 16: KNeighborsClassifier
Python    Classifier 17: LabelPropagation
Python    Classifier 18: LabelSpreading
Python    Classifier 19: LinearDiscriminantAnalysis
Python    Classifier 20: LinearSVC
Python    Classifier 21: LogisticRegression
Python    Classifier 22: LogisticRegressionCV
Python    Classifier 23: MLPClassifier
Python    Classifier 24: MultiOutputClassifier
Python    Classifier 25: MultinomialNB
Python    Classifier 26: NearestCentroid
Python    Classifier 27: NuSVC
Python    Classifier 28: OneVsOneClassifier
Python    Classifier 29: OneVsRestClassifier
Python    Classifier 30: OutputCodeClassifier
Python    Classifier 31: PassiveAggressiveClassifier
Python    Classifier 32: Perceptron
Python    Classifier 33: QuadraticDiscriminantAnalysis
Python    Classifier 34: RadiusNeighborsClassifier
Python    Classifier 35: RandomForestClassifier
Python    Classifier 36: RidgeClassifier
Python    Classifier 37: RidgeClassifierCV
Python    Classifier 38: SGDClassifier
Python    Classifier 39: SVC
Python    Classifier 40: StackingClassifier
Python    Classifier 41: VotingClassifier

Bu sınıflandırıcılar listesinde kolaylık sağlamak için farklı renklerle vurgulanmışlardır. Temel sınıflandırıcılara ihtiyaç duyan modeller sarı renkle vurgulanmıştır, diğer modeller ise bağımsız olarak kullanılabilir.

İleriye baktığımızda, yeşil renkli modellerin ONNX formatına başarıyla aktarıldığını, kırmızı renkli modellerin ise scikit-learn 1.2.2'nin mevcut sürümünde dönüştürme sırasında hatalarla karşılaştığını belirtmek gerekir.


Modellerde farklı çıktı temsilleri

Farklı modellerin çıktı verilerini farklı şekilde temsil ettiği unutulmamalıdır, bu nedenle ONNX'e dönüştürülen modellerle çalışırken dikkatli olunmalıdır.

Fisher'ın iris sınıflandırma görevi için, girdi tensörleri tüm bu modeller için aynı biçime sahiptir:

Information about input tensors in ONNX:
1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]

ONNX modellerinin çıktı tensörleri farklıdır.

1. İleri işleme gerektirmeyen modeller:

  1. SVC Classifier;
  2. LinearSVC Classifier;
  3. NuSVC Classifier;
  4. Radius Neighbors Classifier;
  5. Ridge Classifier;
  6. Ridge Classifier CV.
Information about output tensors in ONNX:
1. Name: label, Data Type: tensor(int64), Shape: [None]
2. Name: probabilities, Data Type: tensor(float), Shape: [None, 3]

Bu modeller sonucu (sınıf numarasını) ileri işleme gerektirmeden ilk çıktı tamsayı tensörü "label" içinde açıkça geri döndürür.

2. Sonuçları ileri işleme gerektiren modeller:

  1. Random Forest Classifier;
  2. Gradient Boosting Classifier;
  3. AdaBoost Classifier;
  4. Bagging Classifier;
  5. K-NN_Classifier;
  6. Decision Tree Classifier;
  7. Logistic Regression Classifier;
  8. Logistic Regression CV Classifier;
  9. Passive-Aggressive Classifier;
  10. Perceptron Classifier;
  11. SGD Classifier;
  12. Gaussian Naive Bayes Classifier;
  13. Multinomial Naive Bayes Classifier;
  14. Complement Naive Bayes Classifier;
  15. Bernoulli Naive Bayes Classifier;
  16. Multilayer Perceptron Classifier;
  17. Linear Discriminant Analysis Classifier;
  18. Hist Gradient Boosting Classifier;
  19. Categorical  Naive Bayes Classifier;
  20. ExtraTree Classifier;
  21. ExtraTrees Classifier.
Information about output tensors in ONNX:
1. Name: output_label, Data Type: tensor(int64), Shape: [None]
2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []

Bu modeller, sınıfların ve her bir sınıfa ait olma olasılıklarının bir listesini geri döndürür.

Bu durumlarda sonucu elde etmek için, seq(map(int64, tensor(float)) (en yüksek olasılığa sahip öğeyi bulma) gibi ileri işleme gereklidir.

Bu nedenle, ONNX modelleriyle çalışırken dikkatli olmak ve bu hususları göz önünde bulundurmak çok önemlidir. Farklı sonuç işlemeye ilişkin bir örnek 2.28.2'deki komut dosyasında sunulmuştur.


iris.mqh

Modelleri MQL5'te tam iris veri kümesi üzerinde test etmek için veri hazırlığı gereklidir. Bu amaçla PrepareIrisDataset() fonksiyonu kullanılacaktır.

Bu fonksiyonları iris.mqh dosyasına taşımak uygundur.

//+------------------------------------------------------------------+
//|                                                         Iris.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"

//+------------------------------------------------------------------+
//| Structure for the IRIS Dataset sample                            |
//+------------------------------------------------------------------+
struct sIRISsample
  {
   int               sample_id;   // sample id (1-150)
   double            features[4]; // SepalLengthCm,SepalWidthCm,PetalLengthCm,PetalWidthCm
   string            class_name;  // class ("Iris-setosa","Iris-versicolor","Iris-virginica")
   int               class_id;    // class id (0,1,2), calculated by function IRISClassID
  };

//--- Iris dataset
sIRISsample ExtIRISDataset[];
int Exttotal=0;

//+------------------------------------------------------------------+
//| Returns class id by class name                                   |
//+------------------------------------------------------------------+
int IRISClassID(string class_name)
  {
//---
   if(class_name=="Iris-setosa")
      return(0);
   else
      if(class_name=="Iris-versicolor")
         return(1);
      else
         if(class_name=="Iris-virginica")
            return(2);
//---
   return(-1);
  }

//+------------------------------------------------------------------+
//| AddSample                                                        |
//+------------------------------------------------------------------+
bool AddSample(const int Id,const double SepalLengthCm,const double SepalWidthCm,const double PetalLengthCm,const double PetalWidthCm, const string Species)
  {
//---
   ExtIRISDataset[Exttotal].sample_id=Id;
//---
   ExtIRISDataset[Exttotal].features[0]=SepalLengthCm;
   ExtIRISDataset[Exttotal].features[1]=SepalWidthCm;
   ExtIRISDataset[Exttotal].features[2]=PetalLengthCm;
   ExtIRISDataset[Exttotal].features[3]=PetalWidthCm;
//---
   ExtIRISDataset[Exttotal].class_name=Species;
   ExtIRISDataset[Exttotal].class_id=IRISClassID(Species);
//---
   Exttotal++;
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| Prepare Iris Dataset                                             |
//+------------------------------------------------------------------+
bool PrepareIrisDataset(sIRISsample &iris_samples[])
  {
   ArrayResize(ExtIRISDataset,150);
   Exttotal=0;
//---
   AddSample(1,5.1,3.5,1.4,0.2,"Iris-setosa");
   AddSample(2,4.9,3.0,1.4,0.2,"Iris-setosa");
   AddSample(3,4.7,3.2,1.3,0.2,"Iris-setosa");
   AddSample(4,4.6,3.1,1.5,0.2,"Iris-setosa");
   AddSample(5,5.0,3.6,1.4,0.2,"Iris-setosa");
   AddSample(6,5.4,3.9,1.7,0.4,"Iris-setosa");
   AddSample(7,4.6,3.4,1.4,0.3,"Iris-setosa");
   AddSample(8,5.0,3.4,1.5,0.2,"Iris-setosa");
   AddSample(9,4.4,2.9,1.4,0.2,"Iris-setosa");
   AddSample(10,4.9,3.1,1.5,0.1,"Iris-setosa");
   AddSample(11,5.4,3.7,1.5,0.2,"Iris-setosa");
   AddSample(12,4.8,3.4,1.6,0.2,"Iris-setosa");
   AddSample(13,4.8,3.0,1.4,0.1,"Iris-setosa");
   AddSample(14,4.3,3.0,1.1,0.1,"Iris-setosa");
   AddSample(15,5.8,4.0,1.2,0.2,"Iris-setosa");
   AddSample(16,5.7,4.4,1.5,0.4,"Iris-setosa");
   AddSample(17,5.4,3.9,1.3,0.4,"Iris-setosa");
   AddSample(18,5.1,3.5,1.4,0.3,"Iris-setosa");
   AddSample(19,5.7,3.8,1.7,0.3,"Iris-setosa");
   AddSample(20,5.1,3.8,1.5,0.3,"Iris-setosa");
   AddSample(21,5.4,3.4,1.7,0.2,"Iris-setosa");
   AddSample(22,5.1,3.7,1.5,0.4,"Iris-setosa");
   AddSample(23,4.6,3.6,1.0,0.2,"Iris-setosa");
   AddSample(24,5.1,3.3,1.7,0.5,"Iris-setosa");
   AddSample(25,4.8,3.4,1.9,0.2,"Iris-setosa");
   AddSample(26,5.0,3.0,1.6,0.2,"Iris-setosa");
   AddSample(27,5.0,3.4,1.6,0.4,"Iris-setosa");
   AddSample(28,5.2,3.5,1.5,0.2,"Iris-setosa");
   AddSample(29,5.2,3.4,1.4,0.2,"Iris-setosa");
   AddSample(30,4.7,3.2,1.6,0.2,"Iris-setosa");
   AddSample(31,4.8,3.1,1.6,0.2,"Iris-setosa");
   AddSample(32,5.4,3.4,1.5,0.4,"Iris-setosa");
   AddSample(33,5.2,4.1,1.5,0.1,"Iris-setosa");
   AddSample(34,5.5,4.2,1.4,0.2,"Iris-setosa");
   AddSample(35,4.9,3.1,1.5,0.2,"Iris-setosa");
   AddSample(36,5.0,3.2,1.2,0.2,"Iris-setosa");
   AddSample(37,5.5,3.5,1.3,0.2,"Iris-setosa");
   AddSample(38,4.9,3.6,1.4,0.1,"Iris-setosa");
   AddSample(39,4.4,3.0,1.3,0.2,"Iris-setosa");
   AddSample(40,5.1,3.4,1.5,0.2,"Iris-setosa");
   AddSample(41,5.0,3.5,1.3,0.3,"Iris-setosa");
   AddSample(42,4.5,2.3,1.3,0.3,"Iris-setosa");
   AddSample(43,4.4,3.2,1.3,0.2,"Iris-setosa");
   AddSample(44,5.0,3.5,1.6,0.6,"Iris-setosa");
   AddSample(45,5.1,3.8,1.9,0.4,"Iris-setosa");
   AddSample(46,4.8,3.0,1.4,0.3,"Iris-setosa");
   AddSample(47,5.1,3.8,1.6,0.2,"Iris-setosa");
   AddSample(48,4.6,3.2,1.4,0.2,"Iris-setosa");
   AddSample(49,5.3,3.7,1.5,0.2,"Iris-setosa");
   AddSample(50,5.0,3.3,1.4,0.2,"Iris-setosa");
   AddSample(51,7.0,3.2,4.7,1.4,"Iris-versicolor");
   AddSample(52,6.4,3.2,4.5,1.5,"Iris-versicolor");
   AddSample(53,6.9,3.1,4.9,1.5,"Iris-versicolor");
   AddSample(54,5.5,2.3,4.0,1.3,"Iris-versicolor");
   AddSample(55,6.5,2.8,4.6,1.5,"Iris-versicolor");
   AddSample(56,5.7,2.8,4.5,1.3,"Iris-versicolor");
   AddSample(57,6.3,3.3,4.7,1.6,"Iris-versicolor");
   AddSample(58,4.9,2.4,3.3,1.0,"Iris-versicolor");
   AddSample(59,6.6,2.9,4.6,1.3,"Iris-versicolor");
   AddSample(60,5.2,2.7,3.9,1.4,"Iris-versicolor");
   AddSample(61,5.0,2.0,3.5,1.0,"Iris-versicolor");
   AddSample(62,5.9,3.0,4.2,1.5,"Iris-versicolor");
   AddSample(63,6.0,2.2,4.0,1.0,"Iris-versicolor");
   AddSample(64,6.1,2.9,4.7,1.4,"Iris-versicolor");
   AddSample(65,5.6,2.9,3.6,1.3,"Iris-versicolor");
   AddSample(66,6.7,3.1,4.4,1.4,"Iris-versicolor");
   AddSample(67,5.6,3.0,4.5,1.5,"Iris-versicolor");
   AddSample(68,5.8,2.7,4.1,1.0,"Iris-versicolor");
   AddSample(69,6.2,2.2,4.5,1.5,"Iris-versicolor");
   AddSample(70,5.6,2.5,3.9,1.1,"Iris-versicolor");
   AddSample(71,5.9,3.2,4.8,1.8,"Iris-versicolor");
   AddSample(72,6.1,2.8,4.0,1.3,"Iris-versicolor");
   AddSample(73,6.3,2.5,4.9,1.5,"Iris-versicolor");
   AddSample(74,6.1,2.8,4.7,1.2,"Iris-versicolor");
   AddSample(75,6.4,2.9,4.3,1.3,"Iris-versicolor");
   AddSample(76,6.6,3.0,4.4,1.4,"Iris-versicolor");
   AddSample(77,6.8,2.8,4.8,1.4,"Iris-versicolor");
   AddSample(78,6.7,3.0,5.0,1.7,"Iris-versicolor");
   AddSample(79,6.0,2.9,4.5,1.5,"Iris-versicolor");
   AddSample(80,5.7,2.6,3.5,1.0,"Iris-versicolor");
   AddSample(81,5.5,2.4,3.8,1.1,"Iris-versicolor");
   AddSample(82,5.5,2.4,3.7,1.0,"Iris-versicolor");
   AddSample(83,5.8,2.7,3.9,1.2,"Iris-versicolor");
   AddSample(84,6.0,2.7,5.1,1.6,"Iris-versicolor");
   AddSample(85,5.4,3.0,4.5,1.5,"Iris-versicolor");
   AddSample(86,6.0,3.4,4.5,1.6,"Iris-versicolor");
   AddSample(87,6.7,3.1,4.7,1.5,"Iris-versicolor");
   AddSample(88,6.3,2.3,4.4,1.3,"Iris-versicolor");
   AddSample(89,5.6,3.0,4.1,1.3,"Iris-versicolor");
   AddSample(90,5.5,2.5,4.0,1.3,"Iris-versicolor");
   AddSample(91,5.5,2.6,4.4,1.2,"Iris-versicolor");
   AddSample(92,6.1,3.0,4.6,1.4,"Iris-versicolor");
   AddSample(93,5.8,2.6,4.0,1.2,"Iris-versicolor");
   AddSample(94,5.0,2.3,3.3,1.0,"Iris-versicolor");
   AddSample(95,5.6,2.7,4.2,1.3,"Iris-versicolor");
   AddSample(96,5.7,3.0,4.2,1.2,"Iris-versicolor");
   AddSample(97,5.7,2.9,4.2,1.3,"Iris-versicolor");
   AddSample(98,6.2,2.9,4.3,1.3,"Iris-versicolor");
   AddSample(99,5.1,2.5,3.0,1.1,"Iris-versicolor");
   AddSample(100,5.7,2.8,4.1,1.3,"Iris-versicolor");
   AddSample(101,6.3,3.3,6.0,2.5,"Iris-virginica");
   AddSample(102,5.8,2.7,5.1,1.9,"Iris-virginica");
   AddSample(103,7.1,3.0,5.9,2.1,"Iris-virginica");
   AddSample(104,6.3,2.9,5.6,1.8,"Iris-virginica");
   AddSample(105,6.5,3.0,5.8,2.2,"Iris-virginica");
   AddSample(106,7.6,3.0,6.6,2.1,"Iris-virginica");
   AddSample(107,4.9,2.5,4.5,1.7,"Iris-virginica");
   AddSample(108,7.3,2.9,6.3,1.8,"Iris-virginica");
   AddSample(109,6.7,2.5,5.8,1.8,"Iris-virginica");
   AddSample(110,7.2,3.6,6.1,2.5,"Iris-virginica");
   AddSample(111,6.5,3.2,5.1,2.0,"Iris-virginica");
   AddSample(112,6.4,2.7,5.3,1.9,"Iris-virginica");
   AddSample(113,6.8,3.0,5.5,2.1,"Iris-virginica");
   AddSample(114,5.7,2.5,5.0,2.0,"Iris-virginica");
   AddSample(115,5.8,2.8,5.1,2.4,"Iris-virginica");
   AddSample(116,6.4,3.2,5.3,2.3,"Iris-virginica");
   AddSample(117,6.5,3.0,5.5,1.8,"Iris-virginica");
   AddSample(118,7.7,3.8,6.7,2.2,"Iris-virginica");
   AddSample(119,7.7,2.6,6.9,2.3,"Iris-virginica");
   AddSample(120,6.0,2.2,5.0,1.5,"Iris-virginica");
   AddSample(121,6.9,3.2,5.7,2.3,"Iris-virginica");
   AddSample(122,5.6,2.8,4.9,2.0,"Iris-virginica");
   AddSample(123,7.7,2.8,6.7,2.0,"Iris-virginica");
   AddSample(124,6.3,2.7,4.9,1.8,"Iris-virginica");
   AddSample(125,6.7,3.3,5.7,2.1,"Iris-virginica");
   AddSample(126,7.2,3.2,6.0,1.8,"Iris-virginica");
   AddSample(127,6.2,2.8,4.8,1.8,"Iris-virginica");
   AddSample(128,6.1,3.0,4.9,1.8,"Iris-virginica");
   AddSample(129,6.4,2.8,5.6,2.1,"Iris-virginica");
   AddSample(130,7.2,3.0,5.8,1.6,"Iris-virginica");
   AddSample(131,7.4,2.8,6.1,1.9,"Iris-virginica");
   AddSample(132,7.9,3.8,6.4,2.0,"Iris-virginica");
   AddSample(133,6.4,2.8,5.6,2.2,"Iris-virginica");
   AddSample(134,6.3,2.8,5.1,1.5,"Iris-virginica");
   AddSample(135,6.1,2.6,5.6,1.4,"Iris-virginica");
   AddSample(136,7.7,3.0,6.1,2.3,"Iris-virginica");
   AddSample(137,6.3,3.4,5.6,2.4,"Iris-virginica");
   AddSample(138,6.4,3.1,5.5,1.8,"Iris-virginica");
   AddSample(139,6.0,3.0,4.8,1.8,"Iris-virginica");
   AddSample(140,6.9,3.1,5.4,2.1,"Iris-virginica");
   AddSample(141,6.7,3.1,5.6,2.4,"Iris-virginica");
   AddSample(142,6.9,3.1,5.1,2.3,"Iris-virginica");
   AddSample(143,5.8,2.7,5.1,1.9,"Iris-virginica");
   AddSample(144,6.8,3.2,5.9,2.3,"Iris-virginica");
   AddSample(145,6.7,3.3,5.7,2.5,"Iris-virginica");
   AddSample(146,6.7,3.0,5.2,2.3,"Iris-virginica");
   AddSample(147,6.3,2.5,5.0,1.9,"Iris-virginica");
   AddSample(148,6.5,3.0,5.2,2.0,"Iris-virginica");
   AddSample(149,6.2,3.4,5.4,2.3,"Iris-virginica");
   AddSample(150,5.9,3.0,5.1,1.8,"Iris-virginica");
//---
   ArrayResize(iris_samples,150);
   for(int i=0; i<Exttotal; i++)
     {
      iris_samples[i]=ExtIRISDataset[i];
     }
//---
   return(true);
  }
//+------------------------------------------------------------------+


Sınıflandırma yöntemleri hakkında not: SVC, LinearSVC ve NuSVC

Üç popüler sınıflandırma yöntemini karşılaştıralım: SVC (Support Vector Classification), LinearSVC (Linear Support Vector Classification) ve NuSVC (Nu Support Vector Classification).

Çalışma prensipleri:

    SVC (Support Vector Classification)
        Çalışma prensibi: SVC, sınıflar arasındaki marjın maksimize edilmesine dayanan bir sınıflandırma yöntemidir. Sınıfları maksimum düzeyde ayıran ve hiperdüzleme en yakın noktalar olan destek vektörlerini destekleyen optimum bir ayırıcı hiperdüzlem arar.
        Çekirdek fonksiyonları: SVC lineer, radyal temel fonksiyon (RBF), polinom vb. gibi çeşitli çekirdek fonksiyonları kullanabilir. Çekirdek fonksiyonu, optimum hiperdüzlemi bulmak için verilerin nasıl dönüştürüleceğini belirler.

    LinearSVC (Linear Support Vector Classification)
        Çalışma prensibi: LinearSVC, lineer sınıflandırma konusunda özelleşmiş bir SVC çeşididir. Çekirdek fonksiyonlarını kullanmadan optimum bir doğrusal ayırıcı hiperdüzlem arar. Bu, büyük hacimli verilerle çalışırken daha hızlı ve daha verimli olmasını sağlar.

    NuSVC (Nu Support Vector Classification)
        Çalışma prensibi: NuSVC de destek vektör yöntemlerine dayanır ancak modelin karmaşıklığını ve destek vektörlerinin oranını kontrol eden bir Nu (nu) parametresi ekler. Nu değeri 0 ila 1 aralığındadır ve verilerin ne kadarının destek vektörleri ve hatalar için kullanılabileceğini belirler.

Avantajlar:

    SVC
        Güçlü algoritma: SVC, çekirdek fonksiyonlarının kullanımı sayesinde karmaşık sınıflandırma görevlerinin üstesinden gelebilir ve doğrusal olmayan verilerle çalışabilir.
        Aykırı değerlere karşı dayanıklılık: SVC, ayırıcı hiperdüzlemi oluşturmak için destek vektörlerini kullandığından veri aykırı değerlerine karşı dayanıklıdır.

    LinearSVC
        Yüksek verimlilik: LinearSVC, özellikle çok fazla veri olduğunda ve doğrusal ayırma görev için uygun olduğunda, büyük veri kümeleriyle uğraşırken daha hızlı ve daha verimlidir.
        Lineer sınıflandırma: Problem doğrusal olarak iyi ayrıştırılabiliyorsa, LinearSVC karmaşık çekirdek fonksiyonlarına ihtiyaç duymadan iyi sonuçlar verebilir.

    NuSVC
        Model karmaşıklığı kontrolü: NuSVC'deki Nu parametresi, modelin karmaşıklığını ve verilere uyum ile genelleme arasındaki dengeyi kontrol etmenizi sağlar.
        Aykırı değerlere karşı dayanıklılık: SVC'ye benzer şekilde, NuSVC de aykırı değerlere karşı dayanıklıdır, bu da onu gürültülü verilere sahip görevler için kullanışlı hale getirir.

Sınırlamalar:

    SVC
        Hesaplama karmaşıklığı: SVC büyük veri kümelerinde ve/veya karmaşık çekirdek fonksiyonları kullanıldığında yavaş olabilir.
        Çekirdek hassasiyeti: Doğru çekirdek fonksiyonunu seçmek zorlu bir görev olabilir ve model performansını önemli ölçüde etkileyebilir.

    LinearSVC
        Doğrusallık kısıtı: LinearSVC doğrusal veri ayrımı ile kısıtlanır ve özellikler ile hedef değişken arasında doğrusal olmayan bağımlılıkların olduğu durumlarda kötü performans gösterebilir.

    NuSVC
        Nu parametresinin ayarlanması: Nu parametresinin ayarlanması, optimum sonuçlara ulaşmak için zaman ve deneme gerektirebilir.

Görev karakteristiğine ve veri hacmine bağlı olarak, bu yöntemlerin her biri en iyi seçim olabilir. Denemeler yapmak ve belirli sınıflandırma görevi gereksinimlerine en uygun yöntemi seçmek önemlidir.



2.1. SVC Classifier

Support Vector Classification (SVC) sınıflandırma yöntemi, sınıflandırma görevlerini çözmek için yaygın olarak kullanılan güçlü bir makine öğrenimi algoritmasıdır.

Çalışma prensipleri:

  1. Optimum ayırıcı hiperdüzlem
    Çalışma prensibi: SVC'nin arkasındaki ana fikir, özellik uzayında optimum ayırıcı hiperdüzlemi bulmaktır. Bu hiperdüzlem, farklı sınıflardaki nesneler arasındaki ayrımı en üst düzeye çıkarmalı ve hiperdüzleme en yakın veri noktaları olan destek vektörlerini desteklemelidir.
    Marjı en üst düzeye çıkarma: SVC, destek vektörlerinin hiperdüzleme olan uzaklığı anlamına gelen sınıflar arasındaki marjı maksimize etmeyi amaçlar. Bu, yöntemin aykırı değerlere karşı dayanıklı olmasını ve yeni verilere iyi genelleme yapmasını sağlar.

  2. Çekirdek fonksiyonlarının kullanımı
    Çekirdek fonksiyonları: SVC lineer, radyal temel fonksiyon (RBF), polinom vb. gibi çeşitli çekirdek fonksiyonları kullanabilir. Çekirdek fonksiyonu, orijinal veri uzayında doğrusal ayrılabilirlik olmasa bile, verilerin görevin doğrusal hale geldiği daha yüksek boyutlu bir uzaya yansıtılmasına olanak tanır.
    Çekirdek seçimi: Doğru çekirdek fonksiyonunun seçilmesi SVC modelinin performansını önemli ölçüde etkileyebilir. Doğrusal bir hiperdüzlem her zaman en uygun çözüm değildir.

Avantajlar:

  • Güçlü algoritma. Karmaşık görevlerin üstesinden gelme: SVC, özellikler ve hedef değişken arasında doğrusal olmayan bağımlılıklar olanlar da dahil olmak üzere karmaşık sınıflandırma görevlerini çözebilir.
  • Aykırı değerlere karşı dayanıklılık: Destek vektörlerinin kullanılması, yöntemi veri aykırı değerlerine karşı dayanıklı hale getirir. Tüm veri kümesi yerine destek vektörlerine bağlıdır.
  • Çekirdek esnekliği. Verilere uyarlanabilirlik: Farklı çekirdek fonksiyonları kullanma yeteneği, SVC'nin belirli verilere uyum sağlamasına ve doğrusal olmayan ilişkileri keşfetmesine olanak tanır.
  • İyi genelleme. Yeni verilere genelleme: SVC modeli yeni verilere iyi bir şekilde genellenebilir ve bu da onu tahmin görevleri için kullanışlı hale getirir.

Sınırlamalar:

  • Hesaplama karmaşıklığı. Eğitim süresi: SVC'nin eğitilmesi, özellikle büyük hacimli verilerle veya karmaşık çekirdek fonksiyonlarıyla uğraşırken yavaş olabilir.
  • Çekirdek seçimi. Doğru çekirdek fonksiyonunu seçme: Doğru çekirdek fonksiyonunun seçilmesi denemeler yapmayı gerektirebilir ve veri karakteristiğine bağlıdır.
  • Özellik ölçeklendirmesine duyarlılık. Veri normalleştirme: SVC özellik ölçeklendirmesine duyarlıdır, bu nedenle eğitimden önce verilerin normalleştirilmesi veya standartlaştırılması önerilir.
  • Model yorumlanabilirliği. Yorumlama karmaşıklığı: Doğrusal olmayan çekirdeklerin ve çok sayıda destek vektörünün kullanılması nedeniyle SVC modellerinin yorumlanması karmaşık olabilir.

Özel göreve ve veri hacmine bağlı olarak, SVC yöntemi sınıflandırma görevlerini çözmek için güçlü bir araç olabilir. Bununla birlikte, optimum sonuçlar elde etmek için sınırlamalarını dikkate almak ve parametreleri ayarlamak çok önemlidir.

2.1.1. SVC Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir SVC Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_SVCClassifier.py
# The code demonstrates the process of training SVC model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create an SVC Classifier model with a linear kernel
svc_model = SVC(kernel='linear', C=1.0)

# train the model on the entire dataset
svc_model.fit(X, y)  

# predict classes for the entire dataset
y_pred = svc_model.predict(X) 

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of SVC Classifier model:", accuracy)  

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(svc_model, initial_types=initial_type, target_opset=12) 

# save the model to a file
onnx_filename = data_path +"svc_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of SVC Classifier model in ONNX format:", accuracy_onnx)

MetaEditor'da "Derle" düğmesini kullanarak kodu çalıştırdıktan sonra, yürütme sonuçlarını Günlük sekmesinde görüntüleyebilirsiniz.

Şekil 12. MetaEditor'da Iris_SVMClassifier.py komut dosyasının sonuçları

Şekil 12. MetaEditor'da Iris_SVMClassifier.py komut dosyasının sonuçları

Iris_SVCClassifier.py komut dosyasının çıktısı:

Python    Accuracy of SVC Classifier model: 0.9933333333333333
Python   
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python   
Python               0       1.00      1.00      1.00        50
Python               1       1.00      0.98      0.99        50
Python               2       0.98      1.00      0.99        50
Python   
Python        accuracy                           0.99       150
Python       macro avg       0.99      0.99      0.99       150
Python    weighted avg       0.99      0.99      0.99       150
Python   
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\svc_iris.onnx
Python   
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python   
Python    Information about output tensors in ONNX:
Python    1. Name: label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: probabilities, Data Type: tensor(float), Shape: [None, 3]
Python   
Python    Accuracy of SVC Classifier model in ONNX format: 0.9933333333333333

Burada, ONNX modelinin kaydedildiği yol, ONNX modelinin girdi ve çıktı parametrelerinin türleri ve iris veri setini tanımlamadaki doğruluk hakkında bilgi bulabilirsiniz.

SVM Classifier’ı kullanarak veri kümesini tanımlama doğruluğu %99'dur ve ONNX formatına aktarılan model de aynı doğruluk seviyesini göstermektedir.

Şimdi, 150 veri örneğinin her biri için oluşturulan modeli çalıştırarak bu sonuçları MQL5'te doğrulayacağız. Ek olarak, komut dosyası bir toplu veri işleme örneği de içermektedir.


2.1.2. SVC Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                           Iris_SVCClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "svc_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   ulong input_shape[]= { batch_size, input_data.Range(1)};
   OnnxSetInputShape(model,0,input_shape);
//---
   int output1[];
   float output2[][3];
//---
   ArrayResize(output1,(int)batch_size);
   ArrayResize(output2,(int)batch_size);
//---
   ulong output_shape[]= {batch_size};
   OnnxSetOutputShape(model,0,output_shape);
//---
   ulong output_shape2[]= {batch_size,3};
   OnnxSetOutputShape(model,1,output_shape2);
//---
   bool res=OnnxRun(model,ONNX_DEBUG_LOGS,input_data,output1,output2);
//--- classes are ready in output1[k];
   if(res)
     {
      for(int k=0; k<(int)batch_size; k++)
         model_classes_id[k]=output1[k];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="SVCClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Komut dosyasının yürütülmesinin sonuçları MetaTrader 5 terminalinin "Uzmanlar" sekmesinde görüntülenir.

Iris_SVCClassifier (EURUSD,H1)  model:SVCClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_SVCClassifier (EURUSD,H1)  model:SVCClassifier   correct results: 99.33%
Iris_SVCClassifier (EURUSD,H1)  model=SVCClassifier all samples accuracy=0.993333
Iris_SVCClassifier (EURUSD,H1)  model=SVCClassifier batch test accuracy=1.000000

SVC modeli 150 örnekten 149'unu doğru bir şekilde sınıflandırmıştır ki bu mükemmel bir sonuçtur. Model, iris veri setinde sadece bir sınıflandırma hatası yapmış ve 84 numaralı örnek için sınıf 1 (virginica) yerine sınıf 2 (versicolor) tahmininde bulunmuştur.

Dışa aktarılan ONNX modelinin tam iris veri setindeki doğruluğunun %99.33 olduğunu ve bunun orijinal modelin doğruluğuyla eşleştiğini belirtmek gerekir.


2.1.3. SVC Classifier modelinin ONNX gösterimi

Oluşturulan ONNX modelini MetaEditor'da görüntüleyebilirsiniz.


Şekil 13. MetaEditor'da svc_iris.onnx ONNX modeli

Şekil 13. MetaEditor'da svc_iris.onnx ONNX modeli


Modelin mimarisi hakkında daha ayrıntılı bilgi için Netron'u kullanabilirsiniz. Bunu yapmak için, MetaEditor'da modelin açıklamasındaki "Netron'da aç" düğmesine tıklayın.


Şekil 14. Netron'da svc_iris.onnx ONNX modeli

Şekil 14. Şekil 14. Netron'da svc_iris.onnx ONNX modeli


Ayrıca, fareyi modelde bulunan ONNX operatörlerinin üzerine getirerek, bu operatörlerin parametreleri hakkında bilgi alabilirsiniz (Şekil 15'te SVMClassifier).


Şekil 15. Netron'da svc_iris.onnx ONNX modeli (SVMClassifier ONNX operatör parametreleri)

Şekil 15. Netron'da svc_iris.onnx ONNX modeli (SVMClassifier ONNX operatör parametreleri)



2.2. LinearSVC Classifier

LinearSVC (Linear Support Vector Classification), ikili ve çok sınıflı sınıflandırma görevleri için kullanılan güçlü bir makine öğrenimi algoritmasıdır. Verileri en iyi şekilde ayıran bir hiperdüzlem bulma fikrine dayanır.

LinearSVC’nin prensipleri:

  1. Optimum hiperdüzlemin bulunması: LinearSVC'nin ana fikri, iki veri sınıfını maksimum düzeyde ayıran en uygun hiperdüzlemi bulmaktır. Bir hiperdüzlem, doğrusal bir denklemle tanımlanan çok boyutlu bir düzlemdir.
  2. Marjın en aza indirilmesi: LinearSVC, marjları (veri noktaları ile hiperdüzlem arasındaki mesafeler) en aza indirmeyi amaçlar. Marjlar ne kadar büyük olursa, hiperdüzlem sınıfları o kadar etkili bir şekilde ayırır.
  3. Doğrusal olarak ayrıştırılamayan verilerin işlenmesi: LinearSVC, verileri doğrusal olarak ayrılabilecekleri daha yüksek boyutlu bir uzaya yansıtan çekirdek fonksiyonlarının (kernel trick) kullanımı sayesinde orijinal özellik uzayında doğrusal olarak ayrılamayan verilerle çalışabilir.

LinearSVC'nin avantajları:

  • İyi genelleme: LinearSVC iyi bir genelleme yeteneğine sahiptir ve yeni, görülmemiş veriler üzerinde iyi performans gösterebilir.
  • Verimlilik: LinearSVC büyük veri kümeleri üzerinde hızlı bir şekilde çalışır ve nispeten az hesaplama kaynağı gerektirir.
  • Doğrusal olarak ayrıştırılamayan verilerin işlenmesi: LinearSVC, çekirdek fonksiyonlarını kullanarak doğrusal olarak ayrılamayan verilerle sınıflandırma görevlerini yerine getirebilir.
  • Ölçeklenebilirlik: LinearSVC, çok sayıda özelliğe ve önemli veri hacimlerine sahip görevlerde verimli bir şekilde kullanılabilir.

LinearSVC'nin sınırlamaları:

  • Sadece doğrusal ayırıcı hiperdüzlemler: LinearSVC yalnızca doğrusal ayırıcı hiperdüzlemler oluşturur, bu da doğrusal olmayan bağımlılıklara sahip karmaşık sınıflandırma görevleri için yetersiz olabilir.
  • Parametre seçimi: Doğru parametrelerin seçilmesi (örneğin, düzenlileştirme parametresi) uzman bilgisi veya çapraz doğrulama gerektirebilir.
  • Aykırı değerlere hassasiyet: LinearSVC, verilerdeki aykırı değerlere karşı hassas olabilir ve bu da sınıflandırma kalitesini etkileyebilir.
  • Model yorumlanabilirliği: LinearSVC kullanılarak oluşturulan modeller, diğer bazı yöntemlere kıyasla daha az yorumlanabilir olabilir.

LinearSVC, genelleme, verimlilik ve doğrusal olarak ayrılamayan verileri işleme konusunda üstün olan güçlü bir sınıflandırma algoritmasıdır. Özellikle veriler doğrusal bir hiperdüzlemle ayrılabildiğinde, çeşitli sınıflandırma görevlerinde uygulama alanı bulur. Bununla birlikte, doğrusal olmayan bağımlılıkların modellenmesini gerektiren karmaşık görevler için LinearSVC daha az uygun olabilir ve bu gibi durumlarda, daha karmaşık karar sınırlarına sahip alternatif yöntemler düşünülmelidir.


2.2.1. LinearSVC Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir LinearSVC Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_LinearSVC.py
# The code demonstrates the process of training LinearSVC model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a LinearSVC model
linear_svc_model = LinearSVC(C=1.0, max_iter=10000)

# train the model on the entire dataset
linear_svc_model.fit(X, y)

# predict classes for the entire dataset
y_pred = linear_svc_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of LinearSVC model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(linear_svc_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "linear_svc_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of LinearSVC model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of LinearSVC model: 0.9666666666666667
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.96      0.94      0.95        50
Python               2       0.94      0.96      0.95        50
Python    
Python        accuracy                           0.97       150
Python       macro avg       0.97      0.97      0.97       150
Python    weighted avg       0.97      0.97      0.97       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\linear_svc_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: probabilities, Data Type: tensor(float), Shape: [None, 3]
Python    
Python    Accuracy of LinearSVC model in ONNX format: 0.9666666666666667


2.2.2. LinearSVC Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                               Iris_LinearSVC.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "linear_svc_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   ulong input_shape[]= { batch_size, input_data.Range(1)};
   OnnxSetInputShape(model,0,input_shape);
//---
   int output1[];
   float output2[][3];
//---
   ArrayResize(output1,(int)batch_size);
   ArrayResize(output2,(int)batch_size);
//---
   ulong output_shape[]= {batch_size};
   OnnxSetOutputShape(model,0,output_shape);
//---
   ulong output_shape2[]= {batch_size,3};
   OnnxSetOutputShape(model,1,output_shape2);
//---
   bool res=OnnxRun(model,ONNX_DEBUG_LOGS,input_data,output1,output2);
//--- classes are ready in output1[k];
   if(res)
     {
      for(int k=0; k<(int)batch_size; k++)
         model_classes_id[k]=output1[k];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="LinearSVC";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_LinearSVC (EURUSD,H1)      model:LinearSVC  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_LinearSVC (EURUSD,H1)      model:LinearSVC  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_LinearSVC (EURUSD,H1)      model:LinearSVC  sample=85 FAILED [class=2, true class=1] features=(5.40,3.00,4.50,1.50]
Iris_LinearSVC (EURUSD,H1)      model:LinearSVC  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_LinearSVC (EURUSD,H1)      model:LinearSVC  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_LinearSVC (EURUSD,H1)      model:LinearSVC   correct results: 96.67%
Iris_LinearSVC (EURUSD,H1)      model=LinearSVC all samples accuracy=0.966667
Iris_LinearSVC (EURUSD,H1)      model=LinearSVC batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %96.67'dir ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.2.3. LinearSVC Classifier modelinin ONNX gösterimi

Şekil 16. Netron'da LinearSVC Classifier modelinin ONNX gösterimi

Şekil 16. Netron'da LinearSVC Classifier modelinin ONNX gösterimi


2.3. NuSVC Classifier

Nu-Support Vector Classification (NuSVC) yöntemi, Support Vector Machine (SVM) yaklaşımına dayanan güçlü bir makine öğrenimi algoritmasıdır.

NuSVC’nin prensipleri:

  1. Support Vector Machine (SVM): NuSVC, ikili ve çok sınıflı sınıflandırma görevleri için kullanılan bir SVM çeşididir. SVM'nin temel prensibi, maksimum marjı korurken sınıfları maksimum düzeyde ayıran optimum ayırıcı hiperdüzlemi bulmaktır.
  2. Nu parametresi: NuSVC'deki önemli bir parametre, modelin karmaşıklığını kontrol eden ve destek vektörleri ve hatalar olarak kullanılabilecek örneklem oranını tanımlayan Nu parametresidir (nu). Nu değeri 0 ila 1 arasında değişir; burada 0.5, örneğin yaklaşık yarısının destek vektörleri ve hatalar olarak kullanılacağı anlamına gelir.
  3. Parametre ayarlama: Nu parametresi ve diğer hiperparametreler için en uygun değerlerin belirlenmesi, çapraz doğrulama ve eğitim verileri üzerinde en iyi değerlerin aranmasını gerektirebilir.
  4. Çekirdek fonksiyonları: NuSVC lineer, radyal temel fonksiyon (RBF), polinom vb. gibi çeşitli çekirdek fonksiyonları kullanabilir. Çekirdek fonksiyonu, ayırıcı hiperdüzlemi bulmak için özellik uzayının nasıl dönüştürüleceğini belirler.

NuSVC'nin avantajları:

  • Yüksek boyutlu uzaylarda verimlilik: NuSVC yüksek boyutlu uzaylarda verimli bir şekilde çalışabilir, bu da onu çok sayıda özelliğe sahip görevler için uygun hale getirir.
  • Aykırı değerlere karşı dayanıklılık: SVM ve özellikle NuSVC, destek vektörlerinin kullanımı nedeniyle verilerdeki aykırı değerlere karşı dayanıklıdır.
  • Model karmaşıklığının kontrolü: Nu parametresi, model karmaşıklığının kontrol edilmesine ve genelleme ile veri uyumunun dengelenmesine olanak tanır.
  • İyi genelleme: Özellikle SVM ve NuSVC iyi bir genelleme sergileyerek daha önce görülmemiş yeni veriler üzerinde mükemmel performans sağlar.

NuSVC'nin sınırlamaları:

  • Büyük veri hacimlerinde verimsizlik: NuSVC, hesaplama karmaşıklığı nedeniyle büyük veri hacimleri üzerinde eğitildiğinde verimsiz olabilir.
  • Parametre ayarlama gereksinimi: Nu parametresinin ve çekirdek fonksiyonunun ayarlanması zaman ve hesaplama kaynakları gerektirebilir.
  • Çekirdek fonksiyonu doğrusallığı: NuSVC'nin etkinliği önemli ölçüde çekirdek fonksiyonunun seçimine bağlı olabilir ve bazı görevler için farklı fonksiyonlarla denemeler yapmak gerekebilir.
  • Model yorumlanabilirliği: SVM ve NuSVC mükemmel sonuçlar sağlar, ancak özellikle doğrusal olmayan çekirdekler kullanıldığında modellerinin yorumlanması karmaşık olabilir.

Nu-Support Vector Classification (NuSVC), aykırı değerlere karşı sağlamlık ve iyi genelleme gibi çeşitli avantajlara sahip SVM'ye dayalı güçlü bir sınıflandırma yöntemidir. Bununla birlikte, etkinliği parametre ve çekirdek fonksiyonu seçimine bağlıdır ve büyük veri hacimleri için verimsiz olabilir. Parametreleri dikkatlice seçmek ve yöntemi belirli sınıflandırma görevlerine uyarlamak çok önemlidir.


2.3.1. NuSVC Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir NuSVC Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_NuSVC.py
# The code demonstrates the process of training NuSVC model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.svm import NuSVC
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a NuSVC model
nusvc_model = NuSVC(nu=0.5, kernel='linear')

# train the model on the entire dataset
nusvc_model.fit(X, y)

# predict classes for the entire dataset
y_pred = nusvc_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of NuSVC model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(nusvc_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "nusvc_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of NuSVC model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of NuSVC model: 0.9733333333333334
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.96      0.96      0.96        50
Python               2       0.96      0.96      0.96        50
Python    
Python        accuracy                           0.97       150
Python       macro avg       0.97      0.97      0.97       150
Python    weighted avg       0.97      0.97      0.97       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\nusvc_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: probabilities, Data Type: tensor(float), Shape: [None, 3]
Python    
Python    Accuracy of NuSVC model in ONNX format: 0.9733333333333334


2.3.2. NuSVC Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                                   Iris_NuSVC.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "nusvc_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   ulong input_shape[]= { batch_size, input_data.Range(1)};
   OnnxSetInputShape(model,0,input_shape);
//---
   int output1[];
   float output2[][3];
//---
   ArrayResize(output1,(int)batch_size);
   ArrayResize(output2,(int)batch_size);
//---
   ulong output_shape[]= {batch_size};
   OnnxSetOutputShape(model,0,output_shape);
//---
   ulong output_shape2[]= {batch_size,3};
   OnnxSetOutputShape(model,1,output_shape2);
//---
   bool res=OnnxRun(model,ONNX_DEBUG_LOGS,input_data,output1,output2);
//--- classes are ready in output1[k];
   if(res)
     {
      for(int k=0; k<(int)batch_size; k++)
         model_classes_id[k]=output1[k];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="NuSVC";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_NuSVC (EURUSD,H1)  model:NuSVC  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_NuSVC (EURUSD,H1)  model:NuSVC  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_NuSVC (EURUSD,H1)  model:NuSVC  sample=107 FAILED [class=1, true class=2] features=(4.90,2.50,4.50,1.70]
Iris_NuSVC (EURUSD,H1)  model:NuSVC  sample=139 FAILED [class=1, true class=2] features=(6.00,3.00,4.80,1.80]
Iris_NuSVC (EURUSD,H1)  model:NuSVC   correct results: 97.33%
Iris_NuSVC (EURUSD,H1)  model=NuSVC all samples accuracy=0.973333
Iris_NuSVC (EURUSD,H1)  model=NuSVC batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %97.33'tür ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.3.3. NuSVC Classifier modelinin ONNX gösterimi

Şekil 17. Netron'da NuSVC Classifier modelinin ONNX gösterimi

Şekil 17. Netron'da NuSVC Classifier modelinin ONNX gösterimi


2.4. Radius Neighbors Classifier

Radius Neighbors Classifier, nesneler arasındaki yakınlık ilkesine dayalı sınıflandırma görevleri için kullanılan bir makine öğrenimi yöntemidir. Sabit sayıda en yakın komşunun (K) seçildiği klasik K-Nearest Neighbors (K-NN) Classifier’ın aksine, Radius Neighbors Classifier’da nesneler belirli bir yarıçap içindeki en yakın komşulara olan uzaklıklarına göre sınıflandırılır.

Radius Neighbors Classifier’ın prensipleri:
  1. Yarıçapın belirlenmesi: Radius Neighbors Classifier’ın ana parametresi, bir nesne ile komşuları arasında nesnenin komşu sınıfa yakın olarak kabul edildiği maksimum mesafeyi tanımlayan yarıçaptır.
  2. En yakın komşuları bulma: Eğitim veri kümesindeki diğer tüm nesnelere olan uzaklık her nesne için hesaplanır. Belirtilen yarıçap içinde bulunan nesneler, nesnenin komşuları olarak kabul edilir.
  3. Oylama: Radius Neighbors Classifier, nesnenin sınıfını belirlemek için komşular arasında çoğunluk oylamasını kullanır. Örneğin, komşuların çoğunluğu A sınıfına aitse, nesne de A sınıfı olarak sınıflandırılacaktır.
Radius Neighbors Classifier’ın avantajları:
  • Veri yoğunluğuna uyarlanabilirlik: The Radius Neighbors Classifier, farklı özellik uzayı bölgelerindeki veri yoğunluğunun değişebildiği görevler için uygundur.
  • Farklı sınıf şekilleri ile çalışabilme becerisi: Bu yöntem, sınıfların karmaşık ve doğrusal olmayan şekillere sahip olduğu görevlerde iyi performans gösterir.
  • Aykırı değerler içeren veriler için uygundur: Radius Neighbors Classifier, belirtilen yarıçapın ötesinde bulunan komşuları göz ardı ettiği için aykırı değerlere karşı K-NN'den daha dayanıklıdır.
Radius Neighbors Classifier’ın sınırlamaları:
  • Yarıçap seçimine duyarlılık: Optimum yarıçap değerinin seçilmesi basit olmayan bir görev olabilir ve ayarlama gerektirir.
  • Büyük veri kümelerinde verimsizlik: Büyük veri kümeleri için, tüm nesnelere olan uzaklıkları hesaplamak hesaplama açısından maliyetli olabilir.
  • Veri yoğunluğuna bağımlılık: Veriler özellik uzayında tekdüze olmayan bir yoğunluğa sahip olduğunda bu yöntem daha az verimli olabilir.

Radius Neighbors Classifier, nesne yakınlığının önemli olduğu ve sınıf şekillerinin karmaşık olabileceği durumlarda değerli bir makine öğrenimi yöntemidir. Görüntü analizi, doğal dil işleme vb. çeşitli alanlarda uygulanabilir.


2.4.1. Radius Neighbors Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Radius Neighbors Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_RadiusNeighborsClassifier.py
# The code demonstrates the process of training an Radius Neughbors model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model.
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023 MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.neighbors import RadiusNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Radius Neighbors Classifier model
radius_model = RadiusNeighborsClassifier(radius=1.0)

# train the model on the entire dataset
radius_model.fit(X, y)  

# predict classes for the entire dataset
y_pred = radius_model.predict(X) 

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Radius Neighbors Classifier model:", accuracy)  

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(radius_model, initial_types=initial_type, target_opset=12) 

# save the model to a file
onnx_filename = data_path + "radius_neighbors_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Radius Neighbors Classifier model in ONNX format:", accuracy_onnx)

Iris_RadiusNeighbors.py komut dosyasının sonuçları:

Python    Accuracy of Radius Neighbors Classifier model: 0.9733333333333334
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.94      0.98      0.96        50
Python               2       0.98      0.94      0.96        50
Python    
Python        accuracy                           0.97       150
Python       macro avg       0.97      0.97      0.97       150
Python    weighted avg       0.97      0.97      0.97       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\radius_neighbors_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: probabilities, Data Type: tensor(float), Shape: [None, 3]
Python    
Python    Accuracy of Radius Neighbors Classifier model in ONNX format: 0.9733333333333334

Orijinal modelin doğruluğu ile ONNX formatında dışa aktarılan modelin doğruluğu aynıdır.


2.4.2. Radius Neighbors Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                               Iris_RadiusNeighborsClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "radius_neighbors_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   ulong input_shape[]= { batch_size, input_data.Range(1)};
   OnnxSetInputShape(model,0,input_shape);
//---
   int output1[];
   float output2[][3];
//---
   ArrayResize(output1,(int)batch_size);
   ArrayResize(output2,(int)batch_size);
//---
   ulong output_shape[]= {batch_size};
   OnnxSetOutputShape(model,0,output_shape);
//---
   ulong output_shape2[]= {batch_size,3};
   OnnxSetOutputShape(model,1,output_shape2);
//---
   bool res=OnnxRun(model,ONNX_DEBUG_LOGS,input_data,output1,output2);
//--- classes are ready in output1[k];
   if(res)
     {
      for(int k=0; k<(int)batch_size; k++)
         model_classes_id[k]=output1[k];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="RadiusNeighborsClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_RadiusNeighborsClassifier (EURUSD,H1)      model:RadiusNeighborsClassifier  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_RadiusNeighborsClassifier (EURUSD,H1)      model:RadiusNeighborsClassifier  sample=107 FAILED [class=1, true class=2] features=(4.90,2.50,4.50,1.70]
Iris_RadiusNeighborsClassifier (EURUSD,H1)      model:RadiusNeighborsClassifier  sample=127 FAILED [class=1, true class=2] features=(6.20,2.80,4.80,1.80]
Iris_RadiusNeighborsClassifier (EURUSD,H1)      model:RadiusNeighborsClassifier  sample=139 FAILED [class=1, true class=2] features=(6.00,3.00,4.80,1.80]
Iris_RadiusNeighborsClassifier (EURUSD,H1)      model:RadiusNeighborsClassifier   correct results: 97.33%
Iris_RadiusNeighborsClassifier (EURUSD,H1)      model=RadiusNeighborsClassifier all samples accuracy=0.973333
Iris_RadiusNeighborsClassifier (EURUSD,H1)      model=RadiusNeighborsClassifier batch test accuracy=1.000000

Radius Neighbors Classifier modeli 4 sınıflandırma hatasıyla (78, 107, 127 ve 139 numaralı örnekler) %97.33'lük bir doğruluk oranı göstermiştir.

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %97.33'tür ve bu da orijinal modelin doğruluğuyla eşleşmektedir.


2.4.3. Radius Neighbors Classifier modelinin ONNX gösterimi

Şekil 18. Netron'da Radius Neighbors Classifier modelinin ONNX gösterimi

Şekil 18. Netron'da Radius Neighbors Classifier modelinin ONNX gösterimi


RidgeClassifier ve RidgeClassifierCV yöntemleri hakkında not

RidgeClassifier ve RidgeClassifierCV, Ridge regresyonuna dayanan iki sınıflandırma yöntemidir, ancak parametrelerin ayarlanma şekli ve hiperparametrelerin otomatik olarak seçilmesi bakımından farklılık gösterirler:

RidgeClassifier:

  • RidgeClassifier, ikili ve çok sınıflı sınıflandırma görevleri için kullanılan Ridge regresyonuna dayalı bir sınıflandırma yöntemidir.
  • Çok sınıflı sınıflandırma durumunda, RidgeClassifier görevi birden fazla ikili göreve (bire karşı hepsi) dönüştürür ve her biri için bir model oluşturur.
  • Alfa düzenlileştirme parametresinin kullanıcı tarafından manuel olarak ayarlanması gerekir, yani denemeler veya doğrulama verilerinin analizi yoluyla en uygun alfa değerini seçmeniz gerekir.

RidgeClassifierCV:

  • RidgeClassifierCV, çapraz doğrulama için yerleşik destek ve optimum alfa düzenlileştirme parametresinin otomatik seçimini sağlayan RidgeClassifier'ın bir uzantısıdır.
  • Alfa değerini manuel olarak ayarlamak yerine, RidgeClassifierCV'ye araştırılacak alfa değerlerinin bir listesini sağlayabilir ve çapraz doğrulama yöntemini belirtebilirsiniz (örneğin, cv parametresi aracılığıyla).
  • RidgeClassifierCV, çapraz doğrulama sırasında en iyi performansı gösteren optimum alfa değerini otomatik olarak seçer.

Dolayısıyla, aralarındaki temel fark, alfa düzenlileştirme parametresi için en uygun değerin seçilmesindeki otomasyon seviyesinde yatmaktadır. RidgeClassifier, alfanın manuel olarak ayarlanmasını gerektirirken RidgeClassifierCV, çapraz doğrulama kullanarak optimum alfa değerinin otomatik olarak seçilmesine olanak tanır. Bunlar arasındaki tercih, ihtiyaçlarınıza ve model ayarlama sürecindeki otomasyon isteğinize bağlıdır.


2.5. Ridge Classifier

Ridge Classifier, modelde L2 düzenlileştirme (Ridge regresyonu) içeren bir lojistik regresyon çeşididir. L2 düzenlileştirme, modelin büyük katsayılarına bir ceza ekleyerek aşırı uyumu azaltmaya ve modelin genelleme yeteneğini geliştirmeye yardımcı olur.

Ridge Classifier’ın prensipleri:

  1. Olasılıkların tahmini: Lojistik regresyon gibi, Ridge Classifier da lojistik (sigmoid) bir fonksiyon kullanarak bir nesnenin belirli bir sınıfa ait olma olasılığını modeller.
  2. L2 düzenlileştirme: Ridge Classifier, modelin büyük katsayılarını cezalandıran bir L2 düzenlileştirme terimi ekler. Bu, modelin karmaşıklığını kontrol etmek ve aşırı uyumu azaltmak için yapılır.
  3. Parametre eğitimi: Ridge Classifier modeli, özellikler ve düzenlileştirme parametresi için ağırlıkları (katsayıları) ayarlamak üzere eğitim veri kümesi üzerinde eğitilir.

Ridge Classifier’ın avantajları:

  • Aşırı uyum azaltma: L2 düzenlileştirme, modelin aşırı uyum sağlama eğilimini azaltmaya yardımcı olur, bu da özellikle sınırlı veri olduğunda yararlıdır.
  • Çoklu eşdoğrusallığın yönetimi: Ridge Classifier, özelliklerin birbiriyle yüksek oranda ilişkili olduğu çoklu eşdoğrusallık sorunlarını iyi bir şekilde yönetir.

Ridge Classifier’ın sınırlamaları:

  • Düzenlileştirme parametresi seçimine duyarlılık: Diğer düzenlileştirme yöntemleri gibi, düzenlileştirme parametresi (alfa) için doğru değeri seçmek ayarlama ve değerlendirme gerektirir.
  • Çok sınıflı sınıflandırma kısıtı: Ridge Classifier başlangıçta ikili sınıflandırma için tasarlanmıştır, ancak One-vs-All gibi yaklaşımlar kullanılarak çok sınıflı sınıflandırmaya uyarlanabilir.

Ridge Classifier, aşırı uyumla mücadele etmek ve modelin genelleme yeteneğini geliştirmek için lojistik regresyonun faydalarını düzenlileştirmeyle birleştiren güçlü bir makine öğrenimi yöntemidir. Olasılıksal sınıflandırma ve model karmaşıklığı kontrolünün önemli olduğu çeşitli alanlarda uygulama alanı bulmaktadır.


2.5.1. Ridge Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Ridge Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_RidgeClassifier.py
# The code demonstrates the process of training Ridge Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Ridge Classifier model
ridge_model = RidgeClassifier()

# train the model on the entire dataset
ridge_model.fit(X, y)  

# predict classes for the entire dataset
y_pred = ridge_model.predict(X) 

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Ridge Classifier model:", accuracy)  

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(ridge_model, initial_types=initial_type, target_opset=12) 

# save the model to a file
onnx_filename = data_path + "ridge_classifier_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Ridge Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Ridge Classifier model: 0.8533333333333334
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.87      0.66      0.75        50
Python               2       0.73      0.90      0.80        50
Python    
Python        accuracy                           0.85       150
Python       macro avg       0.86      0.85      0.85       150
Python    weighted avg       0.86      0.85      0.85       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\ridge_classifier_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: probabilities, Data Type: tensor(float), Shape: [None, 3]
Python    
Python    Accuracy of Ridge Classifier model in ONNX format: 0.8533333333333334


2.5.2. Ridge Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                         Iris_RidgeClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "ridge_classifier_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   ulong input_shape[]= { batch_size, input_data.Range(1)};
   OnnxSetInputShape(model,0,input_shape);
//---
   int output1[];
   float output2[][3];
//---
   ArrayResize(output1,(int)batch_size);
   ArrayResize(output2,(int)batch_size);
//---
   ulong output_shape[]= {batch_size};
   OnnxSetOutputShape(model,0,output_shape);
//---
   ulong output_shape2[]= {batch_size,3};
   OnnxSetOutputShape(model,1,output_shape2);
//---
   bool res=OnnxRun(model,ONNX_DEBUG_LOGS,input_data,output1,output2);
//--- classes are ready in output1[k];
   if(res)
     {
      for(int k=0; k<(int)batch_size; k++)
         model_classes_id[k]=output1[k];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="RidgeClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=51 FAILED [class=2, true class=1] features=(7.00,3.20,4.70,1.40]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=52 FAILED [class=2, true class=1] features=(6.40,3.20,4.50,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=53 FAILED [class=2, true class=1] features=(6.90,3.10,4.90,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=57 FAILED [class=2, true class=1] features=(6.30,3.30,4.70,1.60]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=62 FAILED [class=2, true class=1] features=(5.90,3.00,4.20,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=65 FAILED [class=2, true class=1] features=(5.60,2.90,3.60,1.30]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=66 FAILED [class=2, true class=1] features=(6.70,3.10,4.40,1.40]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=67 FAILED [class=2, true class=1] features=(5.60,3.00,4.50,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=76 FAILED [class=2, true class=1] features=(6.60,3.00,4.40,1.40]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=79 FAILED [class=2, true class=1] features=(6.00,2.90,4.50,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=85 FAILED [class=2, true class=1] features=(5.40,3.00,4.50,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=86 FAILED [class=2, true class=1] features=(6.00,3.40,4.50,1.60]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=87 FAILED [class=2, true class=1] features=(6.70,3.10,4.70,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=89 FAILED [class=2, true class=1] features=(5.60,3.00,4.10,1.30]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=92 FAILED [class=2, true class=1] features=(6.10,3.00,4.60,1.40]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=109 FAILED [class=1, true class=2] features=(6.70,2.50,5.80,1.80]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=120 FAILED [class=1, true class=2] features=(6.00,2.20,5.00,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  sample=135 FAILED [class=1, true class=2] features=(6.10,2.60,5.60,1.40]
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier   correct results: 85.33%
Iris_RidgeClassifier (EURUSD,H1)        model=RidgeClassifier all samples accuracy=0.853333
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  FAILED [class=2, true class=1] features=(7.00,3.20,4.70,1.40)
Iris_RidgeClassifier (EURUSD,H1)        model:RidgeClassifier  FAILED [class=2, true class=1] features=(6.40,3.20,4.50,1.50)
Iris_RidgeClassifier (EURUSD,H1)        model=RidgeClassifier batch test accuracy=0.000000

Tam iris veri kümesinde model, orijinalin doğruluğuna karşılık gelen %85.33'lük bir doğruluk göstermiştir.


2.5.3. Ridge Classifier modelinin ONNX gösterimi

Şekil 19. Netron'da Ridge Classifier modelinin ONNX gösterimi

Şekil 19. Netron'da Ridge Classifier modelinin ONNX gösterimi


2.6. RidgeClassifierCV

RidgeClassifierCV sınıflandırma yöntemi, Ridge regresyonuna dayalı ikili ve çok sınıflı sınıflandırma için güçlü bir algoritmadır.

RidgeClassifierCV'nin prensipleri:

  1. Lineer Ridge regresyonu: RidgeClassifierCV lineer Ridge regresyonuna dayanmaktadır. Bu yöntem, L2 düzenlileştirmenin eklendiği lineer regresyonun bir modifikasyonudur. Düzenlileştirme, özellik ağırlıklarının büyüklüğünü azaltarak aşırı uyumu kontrol etmeye yardımcı olur.
  2. İkili ve çok sınıflı sınıflandırma: RidgeClassifierCV hem ikili sınıflandırma (sadece iki sınıf olduğunda) hem de çok sınıflı sınıflandırma (ikiden fazla sınıf olduğunda) için kullanılabilir. Çok sınıflı sınıflandırma için, görevi birden fazla ikili göreve dönüştürür (bire karşı hepsi) ve her biri için bir model oluşturur.
  3. Düzenlileştirme parametresinin otomatik seçimi: RidgeClassifierCV'nin en önemli avantajlarından biri, çapraz doğrulama için yerleşik desteği ve optimum alfa düzenlileştirme parametresinin otomatik seçimidir. Alfa değerini manuel olarak ayarlamak yerine, yöntem farklı alfa değerleri üzerinde yineleme yapar ve çapraz doğrulamaya dayalı olarak en iyisini seçer.
  4. Çoklu eşdoğrusallığın yönetimi: RidgeClassifierCV, özelliklerin birbiriyle yüksek oranda ilişkili olduğu çoklu eşdoğrusallık sorunlarını iyi bir şekilde yönetir. Düzenlileştirme, her bir özelliğin katkısının kontrol edilmesini sağlayarak modeli korelasyonlu verilere karşı dayanıklı hale getirir.

RidgeClassifierCV'nin avantajları:

  • Otomatik hiperparametre seçimi: RidgeClassifierCV'nin önemli avantajlarından biri, çapraz doğrulama kullanarak en uygun alfa değerini otomatik olarak seçebilmesidir. Bu, farklı alfa değerleriyle denemeler yapma ihtiyacını ortadan kaldırır ve iyi sonuçlar elde etme olasılığını artırır.
  • Aşırı uyum kontrolü: RidgeClassifierCV tarafından sağlanan L2 düzenlileştirme, model karmaşıklığını kontrol etmeye yardımcı olur ve aşırı uyum riskini azaltır. Bu özellikle sınırlı veriye sahip görevler için önemlidir.
  • Şeffaflık ve yorumlanabilirlik: RidgeClassifierCV, yorumlanabilir özellik ağırlıkları sağlayarak her bir özelliğin tahminlere katkısının analiz edilmesine ve özelliklerin önemine ilişkin sonuçlar çıkarılmasına olanak tanır.
  • Verimlilik: Yöntem oldukça verimlidir ve büyük veri kümelerine uygulanabilir.

RidgeClassifierCV'nin sınırlamaları:

  • Doğrusallık: RidgeClassifierCV, özellikler ve hedef değişken arasında doğrusal ilişkiler olduğunu varsayar. Veriler güçlü doğrusal olmayan ilişkiler sergiliyorsa, yöntem yeterince doğru olmayabilir.
  • Özellik ölçeklendirme hassasiyeti: Yöntem, özellik ölçeklendirmesine duyarlıdır. RidgeClassifierCV'yi uygulamadan önce özelliklerin standartlaştırılması veya normalleştirilmesi önerilir.
  • Optimum özellik seçimi: RidgeClassifierCV otomatik özellik seçimi yapmaz, bu nedenle hangi özelliklerin modele dahil edileceğine manuel olarak karar vermeniz gerekir.

RidgeClassifierCV sınıflandırma yöntemi, optimum düzenlileştirme parametresinin otomatik seçimi ile ikili ve çok sınıflı sınıflandırma için güçlü bir araçtır. Aşırı uyum kontrolü, yorumlanabilirliği ve verimliliği, onu çeşitli sınıflandırma görevleri için popüler bir seçim haline getirmektedir. Bununla birlikte, sınırlamalarını, özellikle de özellikler ve hedef değişken arasındaki doğrusal ilişkiler varsayımını akılda tutmak önemlidir.

2.6.1. RidgeClassifierCV modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir RidgeClassifierCV modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_RidgeClassifierCV.py
# The code demonstrates the process of training RidgeClassifierCV model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.linear_model import RidgeClassifierCV
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a RidgeClassifierCV model
ridge_classifier_cv_model = RidgeClassifierCV()

# train the model on the entire dataset
ridge_classifier_cv_model.fit(X, y)

# predict classes for the entire dataset
y_pred = ridge_classifier_cv_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of RidgeClassifierCV model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(ridge_classifier_cv_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "ridge_classifier_cv_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of RidgeClassifierCV model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of RidgeClassifierCV model: 0.8533333333333334
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.87      0.66      0.75        50
Python               2       0.73      0.90      0.80        50
Python    
Python        accuracy                           0.85       150
Python       macro avg       0.86      0.85      0.85       150
Python    weighted avg       0.86      0.85      0.85       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\ridge_classifier_cv_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: probabilities, Data Type: tensor(float), Shape: [None, 3]
Python    
Python    Accuracy of RidgeClassifierCV model in ONNX format: 0.8533333333333334


2.6.2. RidgeClassifierCV modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                       Iris_RidgeClassifierCV.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "ridge_classifier_cv_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   ulong input_shape[]= { batch_size, input_data.Range(1)};
   OnnxSetInputShape(model,0,input_shape);
//---
   int output1[];
   float output2[][3];
//---
   ArrayResize(output1,(int)batch_size);
   ArrayResize(output2,(int)batch_size);
//---
   ulong output_shape[]= {batch_size};
   OnnxSetOutputShape(model,0,output_shape);
//---
   ulong output_shape2[]= {batch_size,3};
   OnnxSetOutputShape(model,1,output_shape2);
//---
   bool res=OnnxRun(model,ONNX_DEBUG_LOGS,input_data,output1,output2);
//--- classes are ready in output1[k];
   if(res)
     {
      for(int k=0; k<(int)batch_size; k++)
         model_classes_id[k]=output1[k];
     }
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="RidgeClassifierCV";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=51 FAILED [class=2, true class=1] features=(7.00,3.20,4.70,1.40]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=52 FAILED [class=2, true class=1] features=(6.40,3.20,4.50,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=53 FAILED [class=2, true class=1] features=(6.90,3.10,4.90,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=57 FAILED [class=2, true class=1] features=(6.30,3.30,4.70,1.60]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=62 FAILED [class=2, true class=1] features=(5.90,3.00,4.20,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=65 FAILED [class=2, true class=1] features=(5.60,2.90,3.60,1.30]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=66 FAILED [class=2, true class=1] features=(6.70,3.10,4.40,1.40]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=67 FAILED [class=2, true class=1] features=(5.60,3.00,4.50,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=76 FAILED [class=2, true class=1] features=(6.60,3.00,4.40,1.40]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=79 FAILED [class=2, true class=1] features=(6.00,2.90,4.50,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=85 FAILED [class=2, true class=1] features=(5.40,3.00,4.50,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=86 FAILED [class=2, true class=1] features=(6.00,3.40,4.50,1.60]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=87 FAILED [class=2, true class=1] features=(6.70,3.10,4.70,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=89 FAILED [class=2, true class=1] features=(5.60,3.00,4.10,1.30]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=92 FAILED [class=2, true class=1] features=(6.10,3.00,4.60,1.40]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=109 FAILED [class=1, true class=2] features=(6.70,2.50,5.80,1.80]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=120 FAILED [class=1, true class=2] features=(6.00,2.20,5.00,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  sample=135 FAILED [class=1, true class=2] features=(6.10,2.60,5.60,1.40]
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV   correct results: 85.33%
Iris_RidgeClassifierCV (EURUSD,H1)      model=RidgeClassifierCV all samples accuracy=0.853333
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  FAILED [class=2, true class=1] features=(7.00,3.20,4.70,1.40)
Iris_RidgeClassifierCV (EURUSD,H1)      model:RidgeClassifierCV  FAILED [class=2, true class=1] features=(6.40,3.20,4.50,1.50)
Iris_RidgeClassifierCV (EURUSD,H1)      model=RidgeClassifierCV batch test accuracy=0.000000

ONNX modelinin performansı, orijinal scikit-learn modelinin performansıyla mükemmel bir şekilde eşleşmektedir (%85.33).


2.6.3. RidgeClassifierCV modelinin ONNX gösterimi

Şekil 20. Netron'da RidgeClassifierCV modelinin ONNX gösterimi

Şekil 20. Netron'da RidgeClassifierCV modelinin ONNX gösterimi



2.7. Random Forest Classifier

Random Forest Classifier, birden fazla karar ağacı oluşturmaya ve sınıflandırma kalitesini artırmak için sonuçlarını birleştirmeye dayanan bir topluluk makine öğrenimi yöntemidir. Bu yöntem, etkinliği ve farklı verilerle çalışma kabiliyeti nedeniyle son derece popülerdir.

Random Forest Classifier’ın prensipleri:

  1. Bagging (Bootstrap Aggregating): Random Forest, eğitim verilerinden değiştirme ile birden fazla alt örneklem (yeniden örnekleme) oluşturmayı içeren torbalama yöntemini kullanır. Her bir alt örneklem için ayrı bir karar ağacı oluşturulur.
  2. Rastgele özellik seçimi: Her bir ağaç oluşturulurken, tüm özellik kümesinden rastgele bir özellik alt kümesi seçilir. Bu, ağaçlar arasında çeşitliliği teşvik eder ve aralarındaki korelasyonları azaltır.
  3. Oylama: Bir nesneyi sınıflandırırken, her ağaç kendi tahminini sunar ve tüm ağaçlar arasında en çok oyu alan sınıf nihai model tahmini olarak seçilir.

Random Forest Classifier’ın avantajları:

  • Yüksek doğruluk: Random Forest tipik olarak birden fazla ağacın sonuçlarının ortalamasını alarak yüksek sınıflandırma doğruluğuna ulaşır.
  • Farklı verileri işleme becerisi: Sayısal ve kategorik özelliklerin yanı sıra farklı yapılardaki verilerle de iyi çalışır.
  • Aşırı uyum direnci: Random Forest yerleşik düzenlileştirmeye sahiptir, bu da onu aşırı uyuma karşı dirençli hale getirir.
  • Özelliğin önemi: Random Forest, özelliklerin önemini değerlendirerek veri bilimcilerin ve özellik mühendislerinin verileri daha iyi anlamasına yardımcı olabilir.

Random Forest Classifier’ın sınırlamaları:

  • Hesaplama karmaşıklığı: Bir Random Forest’ı eğitmek, özellikle çok sayıda ağaç ve özellik söz konusu olduğunda zaman alıcı olabilir.
  • Yorumlanabilirlik zorlukları: Çok sayıda ağaç ve rastgele özellik seçimi nedeniyle modelin yorumlanması zor olabilir.
  • Aykırı değer dayanıklılığı garanti edilmez: Random Forest, veri aykırı değerlerine karşı her zaman dayanıklılık sağlamaz.

Random Forest Classifier, biyotıp, finansal analiz ve metin veri analizi dahil olmak üzere çeşitli alanlarda yaygın olarak kullanılan güçlü bir makine öğrenimi algoritmasıdır. Sınıflandırma ve regresyon görevlerini çözmede başarılıdır ve yüksek genelleme kabiliyetine sahiptir.

2.7.1. Random Forest Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Random Forest Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_RandomForestClassifier.py
# The code demonstrates the process of training Random Forest Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023,2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Random Forest Classifier model
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)

# train the model on the entire dataset
rf_model.fit(X, y)

# predict classes for the entire dataset
y_pred = rf_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Random Forest Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(rf_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "rf_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Random Forest Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Random Forest Classifier model: 1.0
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       1.00      1.00      1.00        50
Python               2       1.00      1.00      1.00        50
Python    
Python        accuracy                           1.00       150
Python       macro avg       1.00      1.00      1.00       150
Python    weighted avg       1.00      1.00      1.00       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\rf_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Random Forest Classifier model in ONNX format: 1.0

Random Forest Classifier modeli (ve ONNX versiyonu) Fisher'ın iris sınıflandırma problemini %100 doğrulukla çözmektedir.


2.7.2. Random Forest Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                  Iris_RandomForestClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "rf_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="RandomForestClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_RandomForestClassifier (EURUSD,H1) model:RandomForestClassifier   correct results: 100.00%
Iris_RandomForestClassifier (EURUSD,H1) model=RandomForestClassifier all samples accuracy=1.000000
Iris_RandomForestClassifier (EURUSD,H1) model=RandomForestClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %100'dür ve bu da orijinal modelin doğruluğuyla eşleşmektedir.


2.7.3. Random Forest Classifier modelinin ONNX gösterimi

Şekil 21. Netron'da Random Forest Classifier modelinin ONNX gösterimi

Şekil 21. Netron'da Random Forest Classifier modelinin ONNX gösterimi


2.8. Gradient Boosting Classifier

Gradyan artırma, en güçlü makine öğrenimi yöntemlerinden biridir ve yüksek doğruluğu ve farklı verilerle çalışma yeteneği sayesinde veri analizi, bilgisayarlı görme, doğal dil işleme ve finansal analiz dahil olmak üzere çok çeşitli alanlarda uygulama alanı bulur. Gradient Boosting Classifier, sınıflandırma görevlerini çözmek için karar ağaçlarının bir bileşimini oluşturan bir topluluk makine öğrenimi yöntemidir. Bu yöntem, yüksek doğruluk elde etme kabiliyeti ve aşırı uyuma karşı direnci nedeniyle popülerdir.


Gradient Boosting Classifier’ın prensipleri:

  1. Karar ağaçları topluluğu: Gradient Boosting Classifier, her ağacın bir önceki ağacın tahminlerini iyileştirmeyi amaçladığı bir karar ağaçları topluluğu oluşturur.
  2. Gradyan iniş: Gradyan artırma, kayıp fonksiyonunu optimize etmek için gradyan inişi kullanır. Kayıp fonksiyonunun gradyanını hesaplayarak ve tahminleri bu gradyana göre güncelleyerek sınıflandırma hatasını en aza indirir.
  3. Ağaç ağırlıklandırma: Bileşimdeki her ağacın bir ağırlığı vardır ve sonunda tüm ağaçlardan gelen tahminler ağırlıkları dikkate alınarak birleştirilir.

Gradient Boosting Classifier’ın avantajları:

  • Yüksek doğruluk: Gradient Boosting Classifier tipik olarak yüksek sınıflandırma doğruluğu sağlar ve en güçlü makine öğrenimi yöntemlerinden biridir.
  • Aşırı uyum direnci: Düzenlileştirme ve gradyan iniş kullanımı sayesinde bu yöntem, özellikle hiperparametreler ayarlanırken aşırı uyuma karşı dirençlidir.
  • Farklı veri tipleriyle çalışabilme becerisi: Gradient Boosting Classifier, sayısal ve kategorik özellikler dahil olmak üzere çeşitli veri türlerini işleyebilir.

Gradient Boosting Classifier’ın sınırlamaları:

  • Hesaplama karmaşıklığı: Gradient Boosting Classifier’ı eğitmek, özellikle çok sayıda ağaç veya derin ağaçlar söz konusu olduğunda hesaplama açısından yoğun olabilir.
  • Yorumlanabilirlik zorlukları: Birden fazla ağacın bileşiminin karmaşıklığı nedeniyle, sonuçları yorumlamak zor olabilir.
  • Küçük veri kümeleri için her zaman uygun değildir: Gradyan artırma genellikle etkili çalışma için önemli miktarda veri gerektirir ve küçük veri kümelerinde aşırı uyuma eğilimli olabilir.

Gradient Boosting Classifier, veri analizi yarışmalarında sıklıkla kullanılan ve çeşitli sınıflandırma görevlerini etkili bir şekilde çözen güçlü bir makine öğrenimi yöntemidir. Verilerdeki karmaşık doğrusal olmayan ilişkileri keşfedebilir ve hiperparametreler uygun şekilde ayarlandığında iyi bir genelleme sergiler.


2.8.1. Gradient Boosting Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Gradient Boosting Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_GradientBoostingClassifier.py
# The code demonstrates the process of training Gradient Boostring Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Gradient Boosting Classifier model
gb_model = GradientBoostingClassifier(n_estimators=100, random_state=42)

# train the model on the entire dataset
gb_model.fit(X, y)

# predict classes for the entire dataset
y_pred = gb_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Gradient Boosting Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(gb_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "gb_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Gradient Boosting Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Gradient Boosting Classifier model: 1.0
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       1.00      1.00      1.00        50
Python               2       1.00      1.00      1.00        50
Python    
Python        accuracy                           1.00       150
Python       macro avg       1.00      1.00      1.00       150
Python    weighted avg       1.00      1.00      1.00       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\gb_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Gradient Boosting Classifier model in ONNX format: 1.0

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %100'dür ve bu da orijinal modelin doğruluğuyla eşleşmektedir.


2.8.2. Gradient Boosting Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                              Iris_GradientBoostingClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "gb_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="GradientBoostingClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_GradientBoostingClassifier (EURUSD,H1)     model:GradientBoostingClassifier   correct results: 100.00%
Iris_GradientBoostingClassifier (EURUSD,H1)     model=GradientBoostingClassifier all samples accuracy=1.000000
Iris_GradientBoostingClassifier (EURUSD,H1)     model=GradientBoostingClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %100'dür ve bu da orijinal modelin doğruluğuyla eşleşmektedir.


2.8.3. Gradient Boosting Classifier modelinin ONNX gösterimi

Şekil 22. Netron'da Gradient Boosting Classifier modelinin ONNX gösterimi

Şekil 22. Netron'da Gradient Boosting Classifier modelinin ONNX gösterimi


2.9. Adaptive Boosting Classifier

AdaBoost (Adaptive Boosting) Classifier, daha güçlü bir algoritma oluşturmak için birden fazla zayıf (örneğin karar ağaçları) sınıflandırıcının sonuçlarını birleştirerek sınıflandırmayı geliştirmek için kullanılan bir topluluk makine öğrenimi yöntemidir.

AdaBoost Classifier’ın prensipleri:

  1. Zayıf sınıflandırıcılar topluluğu: AdaBoost, eğitim setindeki her bir örneklemin ağırlıklarını eşit başlangıç değerleri atayarak başlatır.
  2. Zayıf sınıflandırıcıları eğitme: AdaBoost daha sonra örneklem ağırlıklarını dikkate alarak eğitim seti üzerinde zayıf bir sınıflandırıcıyı (örneğin bir karar ağacı) eğitir. Bu sınıflandırıcı örneklemleri doğru bir şekilde sınıflandırmaya çalışır.
  3. Ağırlık yeniden dağıtımı: AdaBoost, yanlış sınıflandırılmış örneklemlerin ağırlıklarını artırarak ve doğru sınıflandırılmış örneklerin ağırlıklarını azaltarak örnek ağırlıklarını ayarlar.
  4. Bileşim oluşturma: AdaBoost, zayıf sınıflandırıcıları eğitme ve ağırlıkları yeniden dağıtma işlemini birçok kez tekrarlar. Bu zayıf sınıflandırıcıların sonuçları daha sonra her sınıflandırıcının doğruluğuna göre katkıda bulunduğu bir bileşimde birleştirilir.

AdaBoost Classifier’ın avantajları:

  • Yüksek doğruluk: AdaBoost tipik olarak birkaç zayıf sınıflandırıcıyı birleştirerek yüksek sınıflandırma doğruluğu sağlar.
  • Aşırı uyum direnci: AdaBoost yerleşik düzenlileştirmeye sahiptir, bu da onu aşırı uyuma karşı dirençli hale getirir.
  • Çeşitli sınıflandırıcılarla çalışabilme becerisi: AdaBoost farklı temel sınıflandırıcılar kullanabilir ve böylece belirli görevlere uyarlanabilir.

AdaBoost Classifier’ın sınırlamaları:

  • Aykırı değerlere hassasiyet: AdaBoost, önemli bir ağırlığa sahip olabilecekleri için verilerdeki aykırı değerlere karşı hassas olabilir.
  • Karmaşık görevler için her zaman uygun değildir: Bazı karmaşık görevlerde, AdaBoost iyi sonuçlar elde etmek için çok sayıda temel sınıflandırıcı gerektirebilir.
  • Temel sınıflandırıcıların kalitesine bağımlılık: AdaBoost, temel sınıflandırıcılar rastgele tahminden daha iyi olduğunda daha iyi performans gösterir.

AdaBoost Classifier, sınıflandırma görevlerini çözmek için pratikte yaygın olarak kullanılan güçlü bir makine öğrenimi algoritmasıdır. Hem ikili hem de çok sınıflı problemler için çok uygundur ve çeşitli temel sınıflandırıcılara uyarlanabilir.


2.9.1. Adaptive Boosting Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Adaptive Boosting Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_AdaBoostClassifier.py
# The code demonstrates the process of training AdaBoost Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create an AdaBoost Classifier model
adaboost_model = AdaBoostClassifier(n_estimators=50, random_state=42)

# train the model on the entire dataset
adaboost_model.fit(X, y)

# predict classes for the entire dataset
y_pred = adaboost_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of AdaBoost Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(adaboost_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "adaboost_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of AdaBoost Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of AdaBoost Classifier model: 0.96
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.92      0.96      0.94        50
Python               2       0.96      0.92      0.94        50
Python    
Python        accuracy                           0.96       150
Python       macro avg       0.96      0.96      0.96       150
Python    weighted avg       0.96      0.96      0.96       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\adaboost_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of AdaBoost Classifier model in ONNX format: 0.96


2.9.2. Adaptive Boosting Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                      Iris_AdaBoostClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "adaboost_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="AdaBoostClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_AdaBoostClassifier (EURUSD,H1)     model:AdaBoostClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_AdaBoostClassifier (EURUSD,H1)     model:AdaBoostClassifier  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_AdaBoostClassifier (EURUSD,H1)     model:AdaBoostClassifier  sample=120 FAILED [class=1, true class=2] features=(6.00,2.20,5.00,1.50]
Iris_AdaBoostClassifier (EURUSD,H1)     model:AdaBoostClassifier  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_AdaBoostClassifier (EURUSD,H1)     model:AdaBoostClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_AdaBoostClassifier (EURUSD,H1)     model:AdaBoostClassifier  sample=135 FAILED [class=1, true class=2] features=(6.10,2.60,5.60,1.40]
Iris_AdaBoostClassifier (EURUSD,H1)     model:AdaBoostClassifier   correct results: 96.00%
Iris_AdaBoostClassifier (EURUSD,H1)     model=AdaBoostClassifier all samples accuracy=0.960000
Iris_AdaBoostClassifier (EURUSD,H1)     model=AdaBoostClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %96'dır ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.9.3. Adaptive Boosting Classifier modelinin ONNX gösterimi

Şekil 23. Netron'da Adaptive Boosting Classifier modelinin ONNX gösterimi

Şekil 23. Netron'da Adaptive Boosting Classifier modelinin ONNX gösterimi


2.10. Bootstrap Aggregating Classifier

Bagging (Bootstrap Aggregating) Classifier, eğitim verisinden birden fazla rastgele alt örneklem (yeniden örnekleme) oluşturmaya ve her biri üzerinde ayrı modeller oluşturmaya dayanan bir topluluk makine öğrenimi yöntemidir. Sonuçlar daha sonra modelin genelleme yeteneğini geliştirmek için birleştirilir.

Bagging Classifier’ın prensipleri:

  1. Alt örneklemler oluşturma: Bagging, eğitim verisinden değiştirme ile birkaç rastgele alt örneklem (yeniden örnekleme) oluşturarak başlar. Bu da aynı örneklemlerin birden fazla alt örneklemde yer alabileceği ve bazı örneklemlerin atlanabileceği anlamına gelir.
  2. Temel modelleri eğitme: Her bir alt örneklem üzerinde ayrı bir temel model (örneğin bir karar ağacı) eğitilir. Her model diğerlerinden bağımsız olarak eğitilir.
  3. Sonuçların birleştirilmesi: Tüm temel modeller eğitildikten sonra, tahminlerinin sonuçları nihai tahmini elde etmek için birleştirilir. İkili sınıflandırmada bu, çoğunluk oylaması yoluyla yapılabilir.

Bagging Classifier’ın avantajları:

  • Düşük varyans: Bagging, birden fazla temel modelin sonuçlarının ortalamasını alarak modelin varyansını azaltır, bu da daha istikrarlı ve güvenilir tahminlere yol açabilir.
  • Aşırı uyum azaltma: Her bir temel model farklı alt örneklemler üzerinde eğitildiğinden, Bagging modelin aşırı uyum eğilimini azaltabilir.
  • Çok yönlülük: Bagging, farklı veri türlerine ve görevlere uyarlanmaya olanak tanıyan çeşitli temel modeller kullanabilir.

Bagging Classifier’ın sınırlamaları:

  • Yanlılığı iyileştirmez: Bagging varyansı azaltma eğilimindedir ancak modelin yanlılığını çözmez. Temel modeller yanlı olma eğilimindeyse (örneğin, yetersiz uyum), Bagging bu sorunu düzeltmeyecektir.
  • Karmaşık görevler için her zaman uygun değildir: Bazı karmaşık görevlerde, Bagging iyi sonuçlar elde etmek için çok sayıda temel model gerektirebilir.

Bagging Classifier, modelin genelleme yeteneğini artırabilen ve aşırı uyumu azaltabilen etkili bir makine öğrenimi yöntemidir. Çeşitli sınıflandırma ve regresyon görevlerini ele almak için genellikle farklı temel modellerle birlikte kullanılır.


2.10.1. Bootstrap Aggregating Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Bootstrap Aggregating Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_BootstrapAggregatingClassifier.py
# The code demonstrates the process of training Bagging Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.ensemble import BaggingClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Bagging Classifier model with a Decision Tree base estimator
bagging_model = BaggingClassifier(n_estimators=100, random_state=42)

# train the model on the entire dataset
bagging_model.fit(X, y)

# predict classes for the entire dataset
y_pred = bagging_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Bagging Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(bagging_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "bagging_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Bagging Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Bagging Classifier model: 1.0
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       1.00      1.00      1.00        50
Python               2       1.00      1.00      1.00        50
Python    
Python        accuracy                           1.00       150
Python       macro avg       1.00      1.00      1.00       150
Python    weighted avg       1.00      1.00      1.00       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\bagging_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Bagging Classifier model in ONNX format: 1.0

Bootstrap Aggregating Classifier modeli (ve ONNX versiyonu) iris veri setini sınıflandırmada %100 doğruluk elde etmiştir.


2.10.2. Bootstrap Aggregating Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                          Iris_BootstrapAggregatingClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "bagging_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="BootstrapAggregatingClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_BootstrapAggregatingClassifier (EURUSD,H1) model:BootstrapAggregatingClassifier   correct results: 100.00%
Iris_BootstrapAggregatingClassifier (EURUSD,H1) model=BootstrapAggregatingClassifier all samples accuracy=1.000000
Iris_BootstrapAggregatingClassifier (EURUSD,H1) model=BootstrapAggregatingClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri setindeki doğruluğu %100'dür ve bu da orijinal modelin doğruluğu ile tutarlıdır.


2.10.3. Bootstrap Aggregating Classifier modelinin ONNX gösterimi

Şekil 24. Netron'da Bootstrap Aggregating Classifier modelinin ONNX gösterimi

Şekil 24. Netron'da Bootstrap Aggregating Classifier modelinin ONNX gösterimi


2.11. K-Nearest Neighbors (K-NN) Classifier

K-Nearest Neighbors (K-NN) Classifier, veri noktaları arasındaki benzerliğe dayalı sınıflandırma ve regresyon görevlerini çözmek için kullanılan bir makine öğrenimi yöntemidir. Çok boyutlu bir özellik uzayında birbirine yakın nesnelerin benzer karakteristiğe sahip olduğu ve bu nedenle benzer sınıf etiketlerine sahip olabileceği ilkesine göre çalışır.

K-NN Classifier’ın prensipleri:

  1. Yakınlığın belirlenmesi: K-NN Classifier, sınıflandırılacak nesne ile eğitim veri kümesindeki diğer nesneler arasındaki yakınlığı hesaplar. Bu genellikle Öklid mesafesi veya Manhattan mesafesi gibi bir mesafe metriği kullanılarak yapılır.
  2. Komşu sayısının seçilmesi: K parametresi, bir nesneyi sınıflandırmak için kullanılacak en yakın komşu sayısını belirler. Tipik olarak K, göreve ve verilere göre seçilir.
  3. Oylama: K-NN, nesnenin sınıfını belirlemek için en yakın K komşu arasında çoğunluk oylamasını kullanır. Örneğin, K komşunun çoğunluğu A sınıfına aitse, nesne de A sınıfı olarak sınıflandırılacaktır.

K-NN Classifier’ın avantajları:

  • Basitlik ve sezgisellik: K-NN, anlaşılması ve uygulanması kolay, basit ve sezgisel bir yöntemdir.
  • Farklı veri tipleriyle çalışabilme becerisi: K-NN, sayısal, kategorik ve metin verileri dahil olmak üzere çeşitli veri türleri için kullanılabilir.
  • Değişen verilere uyarlanabilirlik: K-NN, verilerdeki değişikliklere hızlı bir şekilde adapte olabilir, bu da onu dinamik verilere sahip görevler için uygun hale getirir.

K-NN Classifier’ın sınırlamaları:

  • K seçimine duyarlılık: Optimum K değerini seçmek basit olmayan bir görev olabilir. Küçük bir K aşırı uyuma yol açabilirken, büyük bir K yetersiz uyuma yol açabilir.
  • Özellik ölçeklendirmesine duyarlılık. K-NN özellik ölçeklendirmesine duyarlıdır, bu nedenle veri normalizasyonu önemli olabilir.
  • Hesaplama karmaşıklığı: Büyük veri kümeleri ve çok sayıda özellik için, tüm nesne çiftleri arasındaki mesafeleri hesaplamak hesaplama açısından maliyetli olabilir.
  • Yorumlanabilirlik eksikliği: K-NN sonuçlarını yorumlamak, özellikle K büyük olduğunda ve çok fazla veri olduğunda zor olabilir.

K-NN Classifier, tavsiye sistemleri, metin sınıflandırma ve örüntü tanıma gibi nesne yakınlığının önemli olduğu görevlerde yararlı olabilecek bir makine öğrenimi yöntemidir. İlk veri analizi ve hızlı model prototipleme için çok uygundur.

2.11.1. K-Nearest Neighbors (K-NN) Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir K-Nearest Neighbors (K-NN) Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_KNearestNeighborsClassifier.py
# The code uses the K-Nearest Neighbors (KNN) Classifier for the Iris dataset, converts the model to ONNX format, saves it, and evaluates its accuracy.
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a K-Nearest Neighbors (KNN) Classifier model
knn_model = KNeighborsClassifier(n_neighbors=3)

# train the model on the entire dataset
knn_model.fit(X, y)

# predict classes for the entire dataset
y_pred = knn_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of KNN Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(knn_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "knn_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of KNN Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of KNN Classifier model: 0.96
Python   
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python   
Python               0       1.00      1.00      1.00        50
Python               1       0.94      0.94      0.94        50
Python               2       0.94      0.94      0.94        50
Python   
Python        accuracy                           0.96       150
Python       macro avg       0.96      0.96      0.96       150
Python    weighted avg       0.96      0.96      0.96       150
Python   
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\knn_iris.onnx
Python   
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python   
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python   
Python    Accuracy of KNN Classifier model in ONNX format: 0.96


2.11.2. K-Nearest Neighbors (K-NN) Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                             Iris_KNearestNeighborsClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "knn_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="KNearestNeighborsClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier  sample=73 FAILED [class=2, true class=1] features=(6.30,2.50,4.90,1.50]
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier  sample=107 FAILED [class=1, true class=2] features=(4.90,2.50,4.50,1.70]
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier  sample=120 FAILED [class=1, true class=2] features=(6.00,2.20,5.00,1.50]
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier   correct results: 96.00%
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model=KNearestNeighborsClassifier all samples accuracy=0.960000
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model:KNearestNeighborsClassifier  FAILED [class=2, true class=1] features=(6.30,2.50,4.90,1.50)
Iris_KNearestNeighborsClassifier (EURUSD,H1)    model=KNearestNeighborsClassifier batch test accuracy=0.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %96'dır ve bu da orijinal modelin doğruluğu ile tutarlıdır.


2.11.3. K-Nearest Neighbors (K-NN) Classifier modelinin ONNX gösterimi

Şekil 25. Netron'da K-Nearest Neighbors Classifier modelinin ONNX gösterimi

Şekil 25. Netron'da K-Nearest Neighbors Classifier modelinin ONNX gösterimi


2.12. Decision Tree Classifier

Decision Tree Classifier, bir karar ağacının oluşturulmasına dayanan sınıflandırma görevleri için kullanılan bir makine öğrenimi yöntemidir. Bu yöntem, özellikler üzerinde bir dizi koşullu test gerçekleştirerek veri kümesini daha küçük alt gruplara ayırır ve bir nesnenin sınıfını ağaçta izlediği yola göre belirler.

Decision Tree Classifier’ın prensipleri:

  1. Karar ağacının oluşturulması: Başlangıçta, tüm veriler ağacın kökünde temsil edilir. Ağacın her bir düğümü için veriler, her bir alt gruptaki belirsizliği (örneğin entropi veya Gini endeksi) en aza indirmeyi amaçlayan bir özelliğin değerlerine dayalı olarak iki veya daha fazla alt gruba ayrılır.
  2. Yinelemeli inşa: Verileri bölme işlemi, ağaç yapraklarına ulaşana kadar yinelemeli olarak gerçekleştirilir. Yapraklar nesnelerin nihai sınıflarını temsil eder.
  3. Karar verme: Bir nesne ağaca girdiğinde, kökten yapraklardan birine doğru bir yol izler ve burada sınıfı o yapraktaki nesnelerin çoğunluğuna göre belirlenir.

Decision Tree Classifier’ın avantajları:

  • Yorumlanabilirlik: Karar ağaçlarının yorumlanması ve görselleştirilmesi kolaydır. Sınıflandırma için kullanılan karar kuralları anlaşılabilirdir.
  • Farklı veri türlerini işleme: Decision Tree Classifier hem sayısal hem de kategorik özelliklerle çalışabilir.
  • Özelliğin önemi: Karar ağaçları, özelliklerin önemini değerlendirerek veri analistlerinin ve özellik mühendislerinin verileri anlamasına yardımcı olabilir.

Decision Tree Classifier’ın sınırlamaları:

  • Aşırı uyum: Büyük ve derin ağaçlar aşırı uyum sağlamaya eğilimli olabilir, bu da onları yeni verilere daha az genelleştirilebilir hale getirir.
  • Gürültüye karşı hassasiyet: Karar ağaçları, verilerdeki gürültü ve aykırı değerlere karşı hassas olabilir.
  • Açgözlü inşa: Karar ağaçları açgözlü bir algoritma kullanılarak oluşturulur ve bu da optimum olmayan global çözümlere yol açabilir.
  • Veri değişikliklerine karşı istikrarsızlık: Verilerdeki küçük değişiklikler ağaç yapısında önemli değişikliklere yol açabilir.

Decision Tree Classifier, özellikle modelin yorumlanabilirliğinin önemli olduğu ve hangi özelliklerin kararı etkilediğini anlamanız gereken durumlarda, sınıflandırma görevleri için yararlı bir makine öğrenimi yöntemidir. Bu yöntem, Random Forest ve Gradient Boosting gibi topluluk yöntemlerinde de kullanılabilir.


2.12.1. Decision Tree Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Decision Tree Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_DecisionTreeClassifier.py
# The code uses the Decision Tree Classifier for the Iris dataset, converts the model to ONNX format, saves it, and evaluates its accuracy.
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Decision Tree Classifier model
decision_tree_model = DecisionTreeClassifier(random_state=42)

# train the model on the entire dataset
decision_tree_model.fit(X, y)

# predict classes for the entire dataset
y_pred = decision_tree_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Decision Tree Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(decision_tree_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "decision_tree_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Decision Tree Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Decision Tree Classifier model: 1.0
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       1.00      1.00      1.00        50
Python               2       1.00      1.00      1.00        50
Python    
Python        accuracy                           1.00       150
Python       macro avg       1.00      1.00      1.00       150
Python    weighted avg       1.00      1.00      1.00       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\decision_tree_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Decision Tree Classifier model in ONNX format: 1.0

Decision Tree Classifier modeli (ve ONNX versiyonu) Fisher'ın iris veri setinin tamamını sınıflandırmada %100 doğruluk göstermiştir.


2.12.2. Decision Tree Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                  Iris_DecisionTreeClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "decision_tree_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="DecisionTreeClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_DecisionTreeClassifier (EURUSD,H1) model:DecisionTreeClassifier   correct results: 100.00%
Iris_DecisionTreeClassifier (EURUSD,H1) model=DecisionTreeClassifier all samples accuracy=1.000000
Iris_DecisionTreeClassifier (EURUSD,H1) model=DecisionTreeClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %100'dür ve bu da orijinal modelin doğruluğuyla eşleşmektedir.


2.12.3. Decision Tree Classifier modelinin ONNX gösterimi

Şekil 26. Netron'da Decision Tree Classifier modelinin ONNX gösterimi

Şekil 26. Netron'da Decision Tree Classifier modelinin ONNX gösterimi


LogisticRegression ve LogisticRegressionCV hakkında not:

LogisticRegression ve LogisticRegressionCV, lojistik regresyon kullanarak ikili sınıflandırma için kullanılan iki sınıflandırıcıdır, ancak model parametrelerinin nasıl ayarlandığı konusunda farklılık gösterirler:

    LogisticRegression:

  • LogisticRegression, iki sınıftan birine ait olma olasılığını modellemek için lojistik fonksiyon kullanan bir sınıflandırıcıdır (ikili sınıflandırma).
  • C (ters düzenlileştirme gücü), ceza (düzenlileştirme türü, örneğin L1 veya L2), çözücü (optimizasyon algoritması) vb. gibi özelleştirme için temel parametreler sağlar.
  • LogisticRegression kullanırken, genellikle parametre değerlerini ve bunların kombinasyonlarını manuel olarak seçer ve ardından modeli veriler üzerinde eğitirsiniz.

    LogisticRegressionCV:

  • LogisticRegressionCV, çapraz doğrulama ve C düzenlileştirme parametresinin optimum değerinin seçilmesi için yerleşik destek sağlayan LogisticRegression'ın bir uzantısıdır.
  • C'yi manuel olarak seçmek yerine, LogisticRegressionCV'ye keşfedilecek C değerlerinin bir listesini iletebilir ve çapraz doğrulama yöntemini belirtebilirsiniz (örneğin, cv parametresi aracılığıyla).
  • LogisticRegressionCV, çapraz doğrulamada en iyi performansı gösteren optimum C değerini otomatik olarak seçer.
  • Bu, özellikle çok fazla veriniz varsa veya hangi C değerini seçeceğinizden emin değilseniz, düzenlileştirmeyi otomatik olarak ayarlamanız gerektiğinde kullanışlıdır.

Dolayısıyla, aralarındaki temel fark parametre ayarlamasındaki otomasyon seviyesinde yatmaktadır. LogisticRegression, C değerinin manuel olarak ayarlanmasını gerektirirken LogisticRegressionCV, çapraz doğrulama yoluyla optimum C değerinin otomatik olarak seçilmesine olanak tanır. Bunlar arasındaki tercih, ihtiyaçlarınıza ve model ayarlama sürecindeki otomasyon isteğinize bağlıdır.



2.13. Logistic Regression Classifier

Logistic Regression Classifier, ikili ve çok sınıflı sınıflandırma görevleri için kullanılan bir makine öğrenimi yöntemidir. Adında "regresyon" olmasına rağmen, lojistik regresyon aslında bir nesnenin sınıflardan birine ait olma olasılığını tahmin eder. Bu olasılıklara dayanarak nihai sınıflandırma kararı verilir.

Logistic Regression Classifier’ın prensipleri:

  1. Olasılık tahmini: Lojistik regresyon, lojistik (sigmoid) fonksiyon kullanarak bir nesnenin belirli bir sınıfa ait olma olasılığını modeller.
  2. Karar sınırı: Tahmin edilen olasılıklara dayanarak, lojistik regresyon sınıfları ayıran karar sınırını belirler. Olasılık belirli bir eşiği (tipik olarak 0.5) aşarsa, nesne bir sınıfta sınıflandırılır; aksi takdirde, başka bir sınıfta sınıflandırılır.
  3. Parametre öğrenme: Lojistik regresyon modeli, kayıp fonksiyonunu en aza indirmek için özelliklerle ilişkili ağırlıkları (katsayıları) ayarlayarak bir eğitim veri kümesi üzerinde eğitilir.

Logistic Regression Classifier’ın avantajları:

  • Basitlik ve yorumlanabilirlik: Lojistik regresyon, özelliklerin sınıf tahminleri üzerindeki etkisine ilişkin kolayca yorumlanabilir sonuçlara sahip basit bir modeldir.
  • Büyük veri kümelerinde verimlilik: Lojistik regresyon, büyük veri kümelerini verimli bir şekilde işleyebilir ve bunlar üzerinde hızlı bir şekilde eğitebilir.
  • Topluluk yöntemlerinde kullanım: Lojistik regresyon, istifleme gibi topluluk yöntemlerinde temel sınıflandırıcı olarak kullanılabilir.

Logistic Regression Classifier’ın sınırlamaları:

  • Doğrusallık: Lojistik regresyon, özellikler ve olasılıkların logaritması arasında doğrusal bir ilişki olduğunu varsayar ve bu da karmaşık görevler için yetersiz olabilir.
  • Çok sınıflı kısıtı: Orijinal haliyle lojistik regresyon ikili sınıflandırma için tasarlanmıştır, ancak çok sınıflı sınıflandırmaya genişletmek için One-vs-All (One-vs-Rest) gibi yöntemler vardır.
  • Aykırı değerlere hassasiyet: Lojistik regresyon, verilerdeki aykırı değerlere karşı hassas olabilir.

Lojistik regresyon, özellikle modelin yorumlanabilirliğinin önemli olduğu ve verilerin doğrusal veya doğrusala yakın bir yapı sergilediği durumlarda, sınıflandırma görevleri için pratikte yaygın olarak kullanılan klasik bir makine öğrenimi yöntemidir. İstatistik ve tıbbi veri analizinde, faktörlerin olayların olasılığı üzerindeki etkisini değerlendirmek için de kullanılır.


2.13.1. Logistic Regression Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Logistic Regression Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_LogisticRegressionClassifier.py
# The code uses the Logistic Regression Classifier for the Iris dataset, converts the model to ONNX format, saves it, and evaluates its accuracy.
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Logistic Regression Classifier model
logistic_regression_model = LogisticRegression(max_iter=1000, random_state=42)

# train the model on the entire dataset
logistic_regression_model.fit(X, y)

# predict classes for the entire dataset
y_pred = logistic_regression_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Logistic Regression Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(logistic_regression_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "logistic_regression_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Logistic Regression Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Logistic Regression Classifier model: 0.9733333333333334
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.98      0.94      0.96        50
Python               2       0.94      0.98      0.96        50
Python    
Python        accuracy                           0.97       150
Python       macro avg       0.97      0.97      0.97       150
Python    weighted avg       0.97      0.97      0.97       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\logistic_regression_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Logistic Regression Classifier model in ONNX format: 0.9733333333333334


2.13.2. Logistic Regression Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                            Iris_LogisticRegressionClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "logistic_regression_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="LogisticRegressionClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+
Çıktı:
Iris_LogisticRegressionClassifier (EURUSD,H1)   model:LogisticRegressionClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_LogisticRegressionClassifier (EURUSD,H1)   model:LogisticRegressionClassifier  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_LogisticRegressionClassifier (EURUSD,H1)   model:LogisticRegressionClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_LogisticRegressionClassifier (EURUSD,H1)   model:LogisticRegressionClassifier  sample=107 FAILED [class=1, true class=2] features=(4.90,2.50,4.50,1.70]
Iris_LogisticRegressionClassifier (EURUSD,H1)   model:LogisticRegressionClassifier   correct results: 97.33%
Iris_LogisticRegressionClassifier (EURUSD,H1)   model=LogisticRegressionClassifier all samples accuracy=0.973333
Iris_LogisticRegressionClassifier (EURUSD,H1)   model=LogisticRegressionClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %97.33'tür ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.13.3. Logistic Regression Classifier modelinin ONNX gösterimi

Şekil 27. Netron'da Logistic Regression Classifier modelinin ONNX gösterimi

Şekil 27. Netron'da Logistic Regression Classifier modelinin ONNX gösterimi


2.14. LogisticRegressionCV Classifier

LogisticRegressionCV (çapraz doğrulamalı lojistik regresyon) ikili sınıflandırma için güçlü ve esnek bir yöntemdir. Bu yöntem yalnızca lojistik regresyona dayalı sınıflandırma modelleri oluşturmanıza izin vermekle kalmaz, aynı zamanda en iyi performansı elde etmek için parametreleri otomatik olarak ayarlar.

LogisticRegressionCV’nin çalışma prensipleri:

  1. Lojistik regresyon: LogisticRegressionCV temel olarak lojistik regresyona dayanır. Lojistik regresyon, bir nesnenin iki sınıftan birine ait olma olasılığını modellemek için kullanılan istatistiksel bir yöntemdir. Bu model, bağımlı değişkenin ikili (iki sınıflı) olduğu veya ikiliye dönüştürülebildiği durumlarda uygulanır.
  2. Çapraz doğrulama: LogisticRegressionCV'nin en önemli avantajı dahili çapraz doğrulamadır. Bu, C düzenlileştirme parametresi için en uygun değeri manuel olarak seçmek yerine, yöntemin otomatik olarak farklı C değerlerini denediği ve çapraz doğrulamada en iyi performansı göstereni seçtiği anlamına gelir.
  3. Optimum C'yi seçme: LogisticRegressionCV, modelin performansını farklı C değerlerinde değerlendirmek için bir çapraz doğrulama stratejisi kullanır. C, model düzenlileştirmenin kapsamını kontrol eden düzenlileştirme parametresidir. Küçük bir C değeri güçlü düzenlileştirmeye işaret ederken, büyük bir C değeri zayıf düzenlileştirmeye işaret eder. Çapraz doğrulama, yetersiz uyum ve aşırı uyumu dengelemek için en uygun C değerinin seçilmesine yardımcı olur.
  4. Düzenlileştirme: LogisticRegressionCV ayrıca L1 (lasso) ve L2 (ridge) düzenlileştirme dahil olmak üzere çeşitli düzenlileştirme türlerini de destekler. Bu düzenlileştirme türleri, modelin genellemesini iyileştirmeye ve aşırı uyumu önlemeye yardımcı olur.

LogisticRegressionCV'nin avantajları:

    Otomatik parametre ayarlama: LogisticRegressionCV'nin başlıca avantajlarından biri, çapraz doğrulama kullanarak en uygun C değerini otomatik olarak seçebilmesidir. Bu, manuel model ayarlama ihtiyacını ortadan kaldırır ve verilere ve göreve odaklanmanızı sağlar.
    Aşırı uyum dayanıklılığı: LogisticRegressionCV tarafından desteklenen düzenlileştirme, modelin karmaşıklığını kontrol etmeye yardımcı olur ve özellikle sınırlı verilerle aşırı uyum riskini azaltır.
    Şeffaflık: Lojistik regresyon yorumlanabilir bir yöntemdir. Her bir özelliğin tahmine katkısını analiz edebilirsiniz, bu da özelliğin önemini anlamak için yararlıdır.
    Yüksek performans: Lojistik regresyon, özellikle büyük hacimli verilerle hızlı ve verimli bir şekilde çalışabilir.

LogisticRegressionCV’nin sınırlamaları:

    Doğrusal bağımlılıklar: LogisticRegressionCV doğrusal ve doğrusala yakın sınıflandırma problemlerini çözmek için uygundur. Özellikler ve hedef değişken arasındaki ilişki yüksek oranda doğrusal değilse, model iyi performans göstermeyebilir.
    Çok sayıda özelliğin işlenmesi: Çok sayıda özellik ile lojistik regresyon, aşırı uyumu önlemek için önemli miktarda veri veya boyut azaltma teknikleri gerektirebilir.
    Veri temsili bağımlılığı: Lojistik regresyonun etkinliği, verilerin nasıl temsil edildiğine ve hangi özelliklerin seçildiğine bağlı olabilir.

LogisticRegressionCV, otomatik parametre ayarlama ve aşırı uyum sağlamlığı ile ikili sınıflandırma için güçlü bir araçtır. Özellikle hızlı bir şekilde yorumlanabilir bir sınıflandırma modeli oluşturmanız gerektiğinde kullanışlıdır. Ancak, verilerin doğrusal veya doğrusala yakın bağımlılıklar sergilediği durumlarda en iyi performansı gösterdiğini unutmamak önemlidir.


2.14.1. LogisticRegressionCV Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir LogisticRegressionCV Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_LogisticRegressionCVClassifier.py
# The code demonstrates the process of training LogisticRegressionCV model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.linear_model import LogisticRegressionCV
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a LogisticRegressionCV model
logistic_regression_model = LogisticRegressionCV(cv=5, max_iter=1000)

# train the model on the entire dataset
logistic_regression_model.fit(X, y)

# predict classes for the entire dataset
y_pred = logistic_regression_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of LogisticRegressionCV model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(logistic_regression_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "logistic_regressioncv_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of LogisticRegressionCV model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of LogisticRegressionCV model: 0.98
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.98      0.96      0.97        50
Python               2       0.96      0.98      0.97        50
Python    
Python        accuracy                           0.98       150
Python       macro avg       0.98      0.98      0.98       150
Python    weighted avg       0.98      0.98      0.98       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\logistic_regression_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of LogisticRegressionCV model in ONNX format: 0.98


2.14.2. LogisticRegressionCV Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                          Iris_LogisticRegressionCVClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "logistic_regressioncv_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="LogisticRegressionCVClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_LogisticRegressionCVClassifier (EURUSD,H1) model:LogisticRegressionCVClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_LogisticRegressionCVClassifier (EURUSD,H1) model:LogisticRegressionCVClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_LogisticRegressionCVClassifier (EURUSD,H1) model:LogisticRegressionCVClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_LogisticRegressionCVClassifier (EURUSD,H1) model:LogisticRegressionCVClassifier   correct results: 98.00%
Iris_LogisticRegressionCVClassifier (EURUSD,H1) model=LogisticRegressionCVClassifier all samples accuracy=0.980000
Iris_LogisticRegressionCVClassifier (EURUSD,H1) model=LogisticRegressionCVClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %98'dir ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.14.3. LogisticRegressionCV Classifier modelinin ONNX gösterimi

Şekil 28. Netron'da LogisticRegressionCV Classifier modelinin ONNX gösterimi

Şekil 28. Netron'da LogisticRegressionCV Classifier modelinin ONNX gösterimi



2.15. Passive-Aggressive (PA) Classifier

Passive-Aggressive (PA) Classifier, sınıflandırma görevleri için kullanılan bir makine öğrenimi yöntemidir. Bu yöntemin ana fikri, sınıflandırma hatalarını en aza indirmek için eğitim sırasında modelin ağırlıklarını (katsayılarını) uyarlamaktır. Passive-Aggressive Classifier, çevrimiçi öğrenme senaryolarında ve verilerin zaman içinde değiştiği durumlarda faydalı olabilir.

Passive-Aggressive Classifier’ın çalışma prensipleri:

  1. Ağırlık uyarlaması: Passive-Aggressive Classifier, stokastik gradyan inişte olduğu gibi modelin ağırlıklarını kayıp fonksiyonunu en aza indirme yönünde güncellemek yerine, ağırlıkları mevcut örnek için sınıflandırma hatasını en aza indiren yönde uyarlar.
  2. Agresifliği sürdürme: Yöntem, modelin ağırlıklarının ne kadar güçlü bir şekilde uyarlanması gerektiğini belirleyen agresiflik (C) adlı bir parametreye sahiptir. Daha büyük C değerleri yöntemi uyarlamada daha agresif hale getirirken, daha küçük değerler daha az agresif hale getirir.

Passive-Aggressive Classifier’ın avantajları:

  • Çevrimiçi öğrenme için uygundur: Passive-Aggressive Classifier yeni veriler geldikçe güncellenebilir, bu da onu verilerin bir akış halinde geldiği çevrimiçi öğrenme görevleri için uygun hale getirir.
  • Veri değişikliklerine uyarlanabilirlik: Yöntem, modeli yeni koşullara uyarladığı için değişen verilerle iyi performans gösterir.

Passive-Aggressive Classifier’ın sınırlamaları:

  • Agresiflik parametresi seçimine duyarlılık: C agresiflik parametresi için en uygun değerin seçilmesi ayarlama gerektirebilir ve veri karakteristiğine bağlıdır.
  • Karmaşık görevler için her zaman uygun değildir: Passive-Aggressive Classifier, karmaşık özellik bağımlılıklarının dikkate alınması gereken karmaşık görevlerde yüksek doğruluk sağlayamayabilir.
  • Ağırlıkların yorumlanması: Bu yöntem kullanılarak elde edilen model ağırlıkları, lineer veya lojistik regresyon kullanılarak elde edilen ağırlıklara kıyasla daha az yorumlanabilir olabilir.

Passive-Aggressive Classifier, değişen verilerle sınıflandırma görevleri ve modelin yeni koşullara hızlı adaptasyonunun çok önemli olduğu durumlar için uygun bir makine öğrenimi yöntemidir. Metin veri analizi, görüntü sınıflandırma vb. görevler de dahil olmak üzere çeşitli alanlarda uygulamalar bulur.


2.15.1. Passive-Aggressive (PA) Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Passive-Aggressive (PA) Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_PassiveAgressiveClassifier.py
# The code uses the Passive-Aggressive (PA) Classifier for the Iris dataset, converts the model to ONNX format, saves it, and evaluates its accuracy.
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Passive-Aggressive (PA) Classifier model
pa_classifier_model = PassiveAggressiveClassifier(max_iter=1000, random_state=42)

# train the model on the entire dataset
pa_classifier_model.fit(X, y)

# predict classes for the entire dataset
y_pred = pa_classifier_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Passive-Aggressive (PA) Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(pa_classifier_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "pa_classifier_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Passive-Aggressive (PA) Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Passive-Aggressive (PA) Classifier model: 0.96
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.96      0.92      0.94        50
Python               2       0.92      0.96      0.94        50
Python    
Python        accuracy                           0.96       150
Python       macro avg       0.96      0.96      0.96       150
Python    weighted avg       0.96      0.96      0.96       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\pa_classifier_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Passive-Aggressive (PA) Classifier model in ONNX format: 0.96


2.15.2. Passive-Aggressive (PA) Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                              Iris_PassiveAgressiveClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "pa_classifier_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="PassiveAgressiveClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_PassiveAgressiveClassifier (EURUSD,H1)     model:PassiveAgressiveClassifier  sample=67 FAILED [class=2, true class=1] features=(5.60,3.00,4.50,1.50]
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model:PassiveAgressiveClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model:PassiveAgressiveClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model:PassiveAgressiveClassifier  sample=85 FAILED [class=2, true class=1] features=(5.40,3.00,4.50,1.50]
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model:PassiveAgressiveClassifier  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model:PassiveAgressiveClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model:PassiveAgressiveClassifier   correct results: 96.00%
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model=PassiveAgressiveClassifier all samples accuracy=0.960000
Iris_PassiveAgressiveClassifier (EURUSD,H1)     model=PassiveAgressiveClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %96'dır ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.15.3. Passive-Aggressive (PA) Classifier modelinin ONNX gösterimi

Şekil 29. Netron'da Passive-Aggressive (PA) Classifier modelinin ONNX gösterimi

Şekil 29. Netron'da Passive-Aggressive (PA) Classifier modelinin ONNX gösterimi

2.16. Perceptron Classifier

Perceptron Classifier, doğrusal bir ayırıcı hiperdüzleme dayalı olarak iki sınıfı ayırmak için kullanılan doğrusal bir ikili sınıflandırıcıdır. En basit ve en eski makine öğrenimi yöntemlerinden biridir ve temel ilkesi, eğitim veri kümesi üzerinde sınıflandırma doğruluğunu en üst düzeye çıkarmak için modelin ağırlıklarını (katsayılarını) eğitmektir.

Perceptron Classifier’ın çalışma prensipleri:

  1. Doğrusal hiperdüzlem: Perceptron, özellik uzayında iki sınıfı ayıran doğrusal bir hiperdüzlem oluşturur. Bu hiperdüzlem, modelin ağırlıkları (katsayıları) tarafından belirlenir.
  2. Ağırlık eğitimi: Başlangıçta, ağırlıklar rastgele veya sıfır olarak başlatılır. Daha sonra, eğitim veri kümesindeki her nesne için, model mevcut ağırlıklara dayanarak sınıfı tahmin eder ve bir hata durumunda bunları ayarlar. Eğitim, tüm nesneler doğru sınıflandırılana veya maksimum yineleme sayısına ulaşılana kadar devam eder.

Perceptron Classifier’ın avantajları:

  • Basitlik: Perceptron çok basit bir algoritmadır, anlaşılması ve uygulanması kolaydır.
  • Yüksek eğitim hızı: Perceptron, özellikle büyük veri kümeleri üzerinde hızlı bir şekilde eğitilebilir ve çevrimiçi öğrenme görevlerinde kullanılabilir.

Perceptron Classifier’ın sınırlamaları:

  • Doğrusal ayrılabilirlik kısıtı: Perceptron yalnızca verilerin doğrusal olarak ayrılabilir olduğu durumlarda iyi çalışır. Veriler doğrusal olarak ayrılamazsa, Perceptron yüksek doğruluk elde edemeyebilir.
  • Başlangıç ağırlıklarına duyarlılık: Ağırlıkların ilk seçimi algoritmanın yakınsamasını etkileyebilir. Kötü başlangıç ağırlığı seçimleri yavaş yakınsamaya veya sınıfları doğru şekilde ayıramayan bir nörona yol açabilir.
  • Olasılıkları belirleyememe: Perceptron, belirli görevler için önemli olabilecek sınıf üyeliğine ilişkin olasılık hesaplamaları sağlamaz.

Perceptron Classifier, verilerin doğrusal olarak ayrılabilir olduğu basit durumlarda yararlı olabilecek ikili sınıflandırma için temel bir algoritmadır. Çok katmanlı sinir ağları gibi daha karmaşık yöntemler için de bir temel oluşturabilir. Verilerin karmaşık yapılara sahip olduğu daha karmaşık görevlerde, lojistik regresyon veya destek vektör makineleri (SVM) gibi diğer yöntemlerin daha yüksek sınıflandırma doğruluğu sağlayabileceğini unutmamak önemlidir.


2.16.1. Perceptron Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Perceptron Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_PerceptronClassifier.py
# The code demonstrates the process of training Perceptron Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.linear_model import Perceptron
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Perceptron Classifier model
perceptron_model = Perceptron(max_iter=1000, random_state=42)

# train the model on the entire dataset
perceptron_model.fit(X, y)

# predict classes for the entire dataset
y_pred = perceptron_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Perceptron Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(perceptron_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "perceptron_classifier_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Perceptron Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Perceptron Classifier model: 0.6133333333333333
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      0.80      0.89        50
Python               1       0.46      1.00      0.63        50
Python               2       1.00      0.04      0.08        50
Python    
Python        accuracy                           0.61       150
Python       macro avg       0.82      0.61      0.53       150
Python    weighted avg       0.82      0.61      0.53       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\perceptron_classifier_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Perceptron Classifier model in ONNX format: 0.6133333333333333


2.16.2. Perceptron Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                    Iris_PerceptronClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include "iris.mqh"
#resource "perceptron_classifier_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="PerceptronClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=2 FAILED [class=1, true class=0] features=(4.90,3.00,1.40,0.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=9 FAILED [class=1, true class=0] features=(4.40,2.90,1.40,0.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=10 FAILED [class=1, true class=0] features=(4.90,3.10,1.50,0.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=13 FAILED [class=1, true class=0] features=(4.80,3.00,1.40,0.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=21 FAILED [class=1, true class=0] features=(5.40,3.40,1.70,0.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=26 FAILED [class=1, true class=0] features=(5.00,3.00,1.60,0.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=31 FAILED [class=1, true class=0] features=(4.80,3.10,1.60,0.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=35 FAILED [class=1, true class=0] features=(4.90,3.10,1.50,0.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=42 FAILED [class=1, true class=0] features=(4.50,2.30,1.30,0.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=46 FAILED [class=1, true class=0] features=(4.80,3.00,1.40,0.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=102 FAILED [class=1, true class=2] features=(5.80,2.70,5.10,1.90]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=103 FAILED [class=1, true class=2] features=(7.10,3.00,5.90,2.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=104 FAILED [class=1, true class=2] features=(6.30,2.90,5.60,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=105 FAILED [class=1, true class=2] features=(6.50,3.00,5.80,2.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=106 FAILED [class=1, true class=2] features=(7.60,3.00,6.60,2.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=107 FAILED [class=1, true class=2] features=(4.90,2.50,4.50,1.70]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=108 FAILED [class=1, true class=2] features=(7.30,2.90,6.30,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=109 FAILED [class=1, true class=2] features=(6.70,2.50,5.80,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=110 FAILED [class=1, true class=2] features=(7.20,3.60,6.10,2.50]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=111 FAILED [class=1, true class=2] features=(6.50,3.20,5.10,2.00]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=112 FAILED [class=1, true class=2] features=(6.40,2.70,5.30,1.90]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=113 FAILED [class=1, true class=2] features=(6.80,3.00,5.50,2.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=114 FAILED [class=1, true class=2] features=(5.70,2.50,5.00,2.00]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=116 FAILED [class=1, true class=2] features=(6.40,3.20,5.30,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=117 FAILED [class=1, true class=2] features=(6.50,3.00,5.50,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=118 FAILED [class=1, true class=2] features=(7.70,3.80,6.70,2.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=119 FAILED [class=1, true class=2] features=(7.70,2.60,6.90,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=120 FAILED [class=1, true class=2] features=(6.00,2.20,5.00,1.50]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=121 FAILED [class=1, true class=2] features=(6.90,3.20,5.70,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=122 FAILED [class=1, true class=2] features=(5.60,2.80,4.90,2.00]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=123 FAILED [class=1, true class=2] features=(7.70,2.80,6.70,2.00]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=124 FAILED [class=1, true class=2] features=(6.30,2.70,4.90,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=125 FAILED [class=1, true class=2] features=(6.70,3.30,5.70,2.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=126 FAILED [class=1, true class=2] features=(7.20,3.20,6.00,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=127 FAILED [class=1, true class=2] features=(6.20,2.80,4.80,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=128 FAILED [class=1, true class=2] features=(6.10,3.00,4.90,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=129 FAILED [class=1, true class=2] features=(6.40,2.80,5.60,2.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=131 FAILED [class=1, true class=2] features=(7.40,2.80,6.10,1.90]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=132 FAILED [class=1, true class=2] features=(7.90,3.80,6.40,2.00]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=133 FAILED [class=1, true class=2] features=(6.40,2.80,5.60,2.20]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=135 FAILED [class=1, true class=2] features=(6.10,2.60,5.60,1.40]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=136 FAILED [class=1, true class=2] features=(7.70,3.00,6.10,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=137 FAILED [class=1, true class=2] features=(6.30,3.40,5.60,2.40]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=138 FAILED [class=1, true class=2] features=(6.40,3.10,5.50,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=139 FAILED [class=1, true class=2] features=(6.00,3.00,4.80,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=140 FAILED [class=1, true class=2] features=(6.90,3.10,5.40,2.10]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=141 FAILED [class=1, true class=2] features=(6.70,3.10,5.60,2.40]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=142 FAILED [class=1, true class=2] features=(6.90,3.10,5.10,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=143 FAILED [class=1, true class=2] features=(5.80,2.70,5.10,1.90]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=144 FAILED [class=1, true class=2] features=(6.80,3.20,5.90,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=145 FAILED [class=1, true class=2] features=(6.70,3.30,5.70,2.50]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=146 FAILED [class=1, true class=2] features=(6.70,3.00,5.20,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=147 FAILED [class=1, true class=2] features=(6.30,2.50,5.00,1.90]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=148 FAILED [class=1, true class=2] features=(6.50,3.00,5.20,2.00]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=149 FAILED [class=1, true class=2] features=(6.20,3.40,5.40,2.30]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  sample=150 FAILED [class=1, true class=2] features=(5.90,3.00,5.10,1.80]
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier   correct results: 61.33%
Iris_PerceptronClassifier (EURUSD,H1)   model=PerceptronClassifier all samples accuracy=0.613333
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  FAILED [class=1, true class=2] features=(6.30,2.70,4.90,1.80)
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  FAILED [class=1, true class=0] features=(4.90,3.10,1.50,0.10)
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  FAILED [class=1, true class=2] features=(5.80,2.70,5.10,1.90)
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  FAILED [class=1, true class=2] features=(7.10,3.00,5.90,2.10)
Iris_PerceptronClassifier (EURUSD,H1)   model:PerceptronClassifier  FAILED [class=1, true class=2] features=(6.30,2.90,5.60,1.80)
Iris_PerceptronClassifier (EURUSD,H1)   model=PerceptronClassifier batch test accuracy=0.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %61.33'tür ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.

2.16.3. Perceptron Classifier modelinin ONNX gösterimi

Şekil 30. Netron'da Perceptron Classifier modelinin ONNX gösterimi

Şekil 30. Netron'da Perceptron Classifier modelinin ONNX gösterimi


2.17. Stochastic Gradient Descent Classifier

SGD Classifier (Stochastic Gradient Descent Classifier), sınıflandırma görevleri için kullanılan bir makine öğrenimi yöntemidir. Doğrusal modellerin özel bir durumudur ve stokastik gradyan iniş kullanılarak eğitilen doğrusal bir sınıflandırıcıdır.

SGD Classifier’ın prensipleri:

  1. Doğrusal hiperdüzlem: SGD Classifier, çok boyutlu özellik uzayında iki sınıfı ayıran doğrusal bir hiperdüzlem oluşturur. Bu hiperdüzlem, modelin ağırlıkları (katsayıları) tarafından belirlenir.
  2. Stokastik gradyan iniş: Yöntem stokastik gradyan iniş kullanılarak eğitilir; bu da ağırlık güncellemelerinin tüm veri kümesi yerine eğitim veri kümesindeki (veya rastgele seçilen bir alt kümedeki) her nesne üzerinde gerçekleştirildiği anlamına gelir. Bu, SGD Classifier’ı büyük hacimli veriler ve çevrimiçi öğrenme için uygun hale getirir.
  3. Kayıp fonksiyonu: SGD Classifier, ikili sınıflandırma için lojistik kayıp fonksiyonu veya çok sınıflı sınıflandırma için softmax kayıp fonksiyonu gibi bir kayıp fonksiyonunu optimize eder.

SGD Classifier’ın avantajları:

  • Eğitim hızı: SGD Classifier, stokastik gradyan iniş sayesinde özellikle büyük hacimli veriler üzerinde hızlı bir şekilde eğitilir.
  • Çevrimiçi öğrenme için uygundur: Bu yöntem, verilerin akış halinde geldiği ve yeni veriler geldikçe modelin güncellenmesi gereken çevrimiçi öğrenme görevleri için çok uygundur.

SGD Classifier’ın sınırlamaları:

  • Parametrelere duyarlılık: SGD Classifier, öğrenme oranı ve düzenlileştirme parametresi gibi dikkatli ayarlama gerektiren birçok hiperparametreye sahiptir.
  • Ağırlık başlatma: Ağırlıkların ilk seçimi yakınsamayı ve model kalitesini etkileyebilir.
  • Yerel minimumlara yakınsama: SGD yönteminin stokastik yapısı nedeniyle, kayıp fonksiyonunun yerel minimumlarına yakınsayabilir ve bu da model kalitesini etkileyebilir.

SGD Classifier, özellikle hızlı işleme gerektiren büyük hacimli verilerle uğraşırken ikili ve çok sınıflı sınıflandırma görevleri için kullanılabilen çok yönlü bir makine öğrenimi yöntemidir. Yüksek sınıflandırma doğruluğu elde etmek için hiperparametrelerini uygun şekilde ayarlamak ve yakınsamayı izlemek önemlidir.


2.17.1. Stochastic Gradient Descent Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir SGD Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_SGDClassifier.py
# The code demonstrates the process of training Stochastic Gradient Descent Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.linear_model import SGDClassifier
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create an SGD Classifier model
sgd_model = SGDClassifier(max_iter=1000, random_state=42)

# train the model on the entire dataset
sgd_model.fit(X, y)

# predict classes for the entire dataset
y_pred = sgd_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of SGD Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(sgd_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "sgd_classifier_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of SGD Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of SGD Classifier model: 0.9333333333333333
Python   
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python   
Python               0       0.96      1.00      0.98        50
Python               1       0.88      0.92      0.90        50
Python               2       0.96      0.88      0.92        50
Python   
Python        accuracy                           0.93       150
Python       macro avg       0.93      0.93      0.93       150
Python    weighted avg       0.93      0.93      0.93       150
Python   
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\perceptron_classifier_iris.onnx
Python   
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python   
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python   
Python    Accuracy of SGD Classifier model in ONNX format: 0.9333333333333333


2.17.2. Stochastic Gradient Descent Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                           Iris_SGDClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "sgd_classifier_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="SGDClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=65 FAILED [class=0, true class=1] features=(5.60,2.90,3.60,1.30]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=86 FAILED [class=0, true class=1] features=(6.00,3.40,4.50,1.60]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=120 FAILED [class=1, true class=2] features=(6.00,2.20,5.00,1.50]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=124 FAILED [class=1, true class=2] features=(6.30,2.70,4.90,1.80]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=127 FAILED [class=1, true class=2] features=(6.20,2.80,4.80,1.80]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  sample=135 FAILED [class=1, true class=2] features=(6.10,2.60,5.60,1.40]
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier   correct results: 93.33%
Iris_SGDClassifier (EURUSD,H1)  model=SGDClassifier all samples accuracy=0.933333
Iris_SGDClassifier (EURUSD,H1)  model:SGDClassifier  FAILED [class=1, true class=2] features=(6.30,2.70,4.90,1.80)
Iris_SGDClassifier (EURUSD,H1)  model=SGDClassifier batch test accuracy=0.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %93.33'tür ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.17.3. Stochastic Gradient Descent Classifier modelinin ONNX gösterimi

Şekil 31. Netron'da Stochastic Gradient Descent Classifier modelinin ONNX gösterimi

Şekil 31. Netron'da Stochastic Gradient Descent Classifier modelinin ONNX gösterimi


2.18. Gaussian Naive Bayes (GNB) Classifier

Gaussian Naive Bayes (GNB) Classifier, sınıflandırma görevleri için kullanılan Bayes olasılık modeline dayalı bir makine öğrenimi yöntemidir. Saf Bayes sınıflandırıcıları ailesinin bir parçasıdır ve tüm özelliklerin bağımsız olduğunu ve normal bir dağılıma sahip olduğunu varsayar.

Gaussian Naive Bayes Classifier’ın prensipleri:

  1. Bayes yaklaşımı: GNB, bir nesnenin her bir sınıfa ait olma olasılığını hesaplamak için Bayes teoremini kullanan Bayes sınıflandırma yaklaşımına dayanmaktadır.
  2. Saf yaklaşım: GNB'deki temel varsayım, tüm özelliklerin bağımsız olduğu ve normal (Gauss) bir dağılım izlediğidir. Bu varsayım saf olarak kabul edilir çünkü gerçek dünya verilerinde özellikler genellikle birbirleriyle ilişkilidir.
  3. Parametre hesaplaması: GNB modeli, her bir sınıftaki her bir özellik için dağılımın parametrelerini (ortalama ve standart sapma) hesaplayarak eğitim veri kümesi üzerinde eğitilir.

Gaussian Naive Bayes Classifier’ın avantajları:

  • Basitlik ve eğitim hızı: GNB çok basit bir algoritmadır ve büyük veri kümelerinde bile hızlı bir şekilde eğitilir.
  • Küçük ve orta ölçekli veriler için etkililik: GNB, özellikle normal özellik dağılımları varsayımı geçerli olduğunda, az veya orta sayıda özelliğe sahip sınıflandırma görevleri için etkili olabilir.

Gaussian Naive Bayes Classifier’ın sınırlamaları:

  • Saf yaklaşım: Özellik bağımsızlığı ve normal dağılım varsayımı, gerçek dünya verileri için aşırı basit ve yanlış olabilir, bu da sınıflandırma doğruluğunun azalmasına neden olur.
  • Aykırı değerlere hassasiyet: GNB, normal dağılımın parametrelerini önemli ölçüde çarpıtabileceğinden verilerdeki aykırı değerlere karşı hassas olabilir.
  • Özellik bağımlılıklarının yakalanamaması: Bağımsızlık varsayımı nedeniyle, GNB özellikler arasındaki bağımlılıkları hesaba katmaz.

Gaussian Naive Bayes Classifier, özellikle normal özellik dağılımları varsayımı yaklaşık olarak karşılandığında, basit sınıflandırma görevleri için iyi bir seçimdir. Bununla birlikte, özelliklerin birbiriyle ilişkili olduğu veya normal bir dağılım izlemediği daha karmaşık görevlerde, destek vektör makineleri (SVM) veya gradyan artırma gibi diğer yöntemler daha doğru sonuçlar sağlayabilir.


2.18.1. Gaussian Naive Bayes (GNB) Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Gaussian Naive Bayes (GNB) Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_GaussianNaiveBayesClassifier.py
# The code demonstrates the process of training Gaussian Naive Bayes Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Gaussian Naive Bayes (GNB) Classifier model
gnb_model = GaussianNB()

# train the model on the entire dataset
gnb_model.fit(X, y)

# predict classes for the entire dataset
y_pred = gnb_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Gaussian Naive Bayes (GNB) Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(gnb_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "gnb_classifier_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Gaussian Naive Bayes (GNB) Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Gaussian Naive Bayes (GNB) Classifier model: 0.96
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.94      0.94      0.94        50
Python               2       0.94      0.94      0.94        50
Python    
Python        accuracy                           0.96       150
Python       macro avg       0.96      0.96      0.96       150
Python    weighted avg       0.96      0.96      0.96       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\gnb_classifier_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Gaussian Naive Bayes (GNB) Classifier model in ONNX format: 0.96


2.18.2. Gaussian Naive Bayes (GNB) Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                            Iris_GaussianNaiveBayesClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "gnb_classifier_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="GaussianNaiveBayesClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model:GaussianNaiveBayesClassifier  sample=53 FAILED [class=2, true class=1] features=(6.90,3.10,4.90,1.50]
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model:GaussianNaiveBayesClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model:GaussianNaiveBayesClassifier  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model:GaussianNaiveBayesClassifier  sample=107 FAILED [class=1, true class=2] features=(4.90,2.50,4.50,1.70]
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model:GaussianNaiveBayesClassifier  sample=120 FAILED [class=1, true class=2] features=(6.00,2.20,5.00,1.50]
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model:GaussianNaiveBayesClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model:GaussianNaiveBayesClassifier   correct results: 96.00%
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model=GaussianNaiveBayesClassifier all samples accuracy=0.960000
Iris_GaussianNaiveBayesClassifier (EURUSD,H1)   model=GaussianNaiveBayesClassifier batch test accuracy=1.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %96'dır ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.18.3. Gaussian Naive Bayes (GNB) Classifier modelinin ONNX gösterimi

Şekil 32. Netron'da Gaussian Naive Bayes (GNB) Classifier modelinin ONNX gösterimi

Şekil 32. Netron'da Gaussian Naive Bayes (GNB) Classifier modelinin ONNX gösterimi


2.19. Multinomial Naive Bayes (MNB) Classifier

Multinomial Naive Bayes (MNB) Classifier, Bayes olasılık modeline dayalı bir makine öğrenme yöntemidir ve özellikle metin işlemede sınıflandırma görevleri için kullanılır. Saf Bayes sınıflandırıcılarının varyantlarından biridir ve özelliklerin metindeki kelime sayısı gibi sayıları temsil ettiğini varsayar.

Multinomial Naive Bayes Classifier’ın prensipleri:

  1. Bayes yaklaşımı: MNB ayrıca, bir nesnenin her sınıfa ait olma olasılığını hesaplamak için Bayes teoremini kullanarak sınıflandırmaya yönelik Bayes yaklaşımını takip eder.
  2. Çok terimli dağılım varsayımı: MNB'deki temel varsayım, özelliklerin metindeki kelime sayısı gibi sayıları temsil ettiği ve çok terimli bir dağılım izlediğidir. Bu varsayım genellikle metinsel veriler için geçerlidir.
  3. Parametre hesaplaması: MNB modeli, her bir sınıftaki her bir özellik için dağılımın parametreleri hesaplanarak eğitim veri kümesi üzerinde eğitilir.

Multinomial Naive Bayes Classifier’ın avantajları:

  • Metin işlemede etkililik: MNB, özellik sayıları varsayımı sayesinde metin sınıflandırması veya spam filtreleme gibi metinsel verilerin analiziyle ilgili görevlerde iyi performans gösterir.
  • Basitlik ve eğitim hızı: Diğer saf Bayes sınıflandırıcıları gibi, MNB de büyük hacimli metin verilerinde bile hızlı bir şekilde eğitilen basit bir algoritmadır.

Multinomial Naive Bayes Classifier’ın sınırlamaları:

  • Saf yaklaşım: Özelliklerin çok terimli dağılımı varsayımı, özellikle özellikler karmaşık yapılara sahip olduğunda, gerçek dünya verileri için aşırı basit ve yanlış olabilir.
  • Kelime sıralamasını hesaba katamama: MNB, belirli metin analizi görevlerinde önemli olabilen metindeki kelimelerin sırasını dikkate almaz.
  • Nadir kelimelere duyarlılık: MNB nadir kelimelere karşı hassas olabilir ve yetersiz sayıda olması sınıflandırma doğruluğunu azaltabilir.

Multinomial Naive Bayes Classifier, özellikle özellikler metindeki kelime sayısı gibi sayılarla ilgili olduğunda, metin analizi görevleri için kullanışlı bir yöntemdir. Metin sınıflandırma, belge kategorizasyonu ve diğer metin analizleri için doğal dil işlemede (NLP) yaygın olarak kullanılmaktadır.

2.19.1. Multinomial Naive Bayes (MNB) Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Multinomial Naive Bayes (MNB) Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_MultinomialNaiveBayesClassifier.py
# The code demonstrates the process of training Multinomial Naive Bayes (MNB) Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Multinomial Naive Bayes (MNB) Classifier model
mnb_model = MultinomialNB()

# train the model on the entire dataset
mnb_model.fit(X, y)

# predict classes for the entire dataset
y_pred = mnb_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Multinomial Naive Bayes (MNB) Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(mnb_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "mnb_classifier_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Multinomial Naive Bayes (MNB) Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Multinomial Naive Bayes (MNB) Classifier model: 0.9533333333333334
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       1.00      1.00      1.00        50
Python               1       0.94      0.92      0.93        50
Python               2       0.92      0.94      0.93        50
Python    
Python        accuracy                           0.95       150
Python       macro avg       0.95      0.95      0.95       150
Python    weighted avg       0.95      0.95      0.95       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\mnb_classifier_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Multinomial Naive Bayes (MNB) Classifier model in ONNX format: 0.9533333333333334


2.19.2. Multinomial Naive Bayes (MNB) Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                         Iris_MultinomialNaiveBayesClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "mnb_classifier_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="MultinomialNaiveBayesClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  sample=69 FAILED [class=2, true class=1] features=(6.20,2.20,4.50,1.50]
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  sample=73 FAILED [class=2, true class=1] features=(6.30,2.50,4.90,1.50]
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  sample=130 FAILED [class=1, true class=2] features=(7.20,3.00,5.80,1.60]
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  sample=132 FAILED [class=1, true class=2] features=(7.90,3.80,6.40,2.00]
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  sample=134 FAILED [class=1, true class=2] features=(6.30,2.80,5.10,1.50]
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier   correct results: 95.33%
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model=MultinomialNaiveBayesClassifier all samples accuracy=0.953333
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model:MultinomialNaiveBayesClassifier  FAILED [class=2, true class=1] features=(6.30,2.50,4.90,1.50)
Iris_MultinomialNaiveBayesClassifier (EURUSD,H1)        model=MultinomialNaiveBayesClassifier batch test accuracy=0.000000

Dışa aktarılan ONNX modelinin tam iris veri kümesi üzerindeki doğruluğu %95.33'tür ve bu da orijinal modelin doğruluğuna karşılık gelmektedir.


2.19.3. Multinomial Naive Bayes (MNB) Classifier modelinin ONNX gösterimi

Şekil 33. Netron'da Multinomial Naive Bayes (MNB) Classifier modelinin ONNX gösterimi

Şekil 33. Netron'da Multinomial Naive Bayes (MNB) Classifier modelinin ONNX gösterimi


2.20. Complement Naive Bayes (CNB) Classifier

Complement Naive Bayes (CNB) Classifier, bir sınıfın diğerinden önemli ölçüde daha yaygın olabileceği dengesiz verilerle çalışmak üzere özel olarak tasarlanmış bir saf Bayes sınıflandırıcı çeşididir. Bu sınıflandırıcı, sınıf dengesizliğini ele almak için klasik saf Bayes yöntemini uyarlar.

Complement Naive Bayes Classifier’ın prensipleri:

  1. Bayes yaklaşımı: Diğer Bayes sınıflandırıcıları gibi CNB de sınıflandırmada Bayes yaklaşımını izler ve bir nesnenin her bir sınıfa ait olma olasılığını hesaplamak için Bayes teoremini kullanır.
  2. Sınıf dengesizliğinin çözülmesi: CNB'nin birincil amacı sınıf dengesizliğini düzeltmektir. CNB, standart saf Bayes yönteminin yaptığı gibi sınıftaki özelliklerin olasılığını dikkate almak yerine, sınıf dışındaki özelliklerin olasılığını dikkate almaya çalışır. Bu, özellikle bir sınıfın diğerine göre önemli ölçüde daha az temsil edildiği durumlarda faydalıdır.
  3. Parametre hesaplaması: CNB modeli, sınıf dışındaki her özellik için dağılımın parametreleri hesaplanarak eğitim veri kümesi üzerinde eğitilir.

Complement Naive Bayes Classifier’ın avantajları:

  • Dengesiz veriler için uygunluk: CNB, sınıfların farklı sıklığa sahip olduğu dengesiz verilerle sınıflandırma görevlerinde iyi performans gösterir.
  • Basitlik ve eğitim hızı: Diğer saf Bayes sınıflandırıcıları gibi CNB de büyük hacimli veriler üzerinde bile hızlı bir şekilde eğitilen basit bir algoritmadır.

Complement Naive Bayes Classifier’ın sınırlamaları:

  • Düzenlileştirme parametresi seçimine duyarlılık: Diğer Bayes yöntemlerinde olduğu gibi, düzenlileştirme parametresi için doğru değerin seçilmesi ayarlama ve değerlendirme gerektirebilir.
  • Saf yaklaşım: Diğer saf Bayes sınıflandırıcıları gibi CNB de özellik bağımsızlığı varsayımını yapar ve bu varsayım bazı görevler için aşırı basit olabilir.

Complement Naive Bayes Classifier, özellikle bir sınıfın diğerinden önemli ölçüde daha az temsil edildiği durumlarda, dengesiz verilere sahip sınıflandırma görevleri için iyi bir seçimdir. Görüş analizi veya spam filtreleme gibi kelimelerin sınıflar arasında büyük ölçüde dengesiz olabileceği metin sınıflandırma görevlerinde özellikle yararlı olabilir.

2.20.1. Complement Naive Bayes (CNB) Classifier modelini oluşturmak için kod

Bu kod, iris veri kümesi üzerinde bir Complement Naive Bayes (CNB) Classifier modelinin eğitilmesi, ONNX formatına aktarılması ve ONNX modeli kullanılarak sınıflandırma yapılması sürecini göstermektedir. Ayrıca hem orijinal modelin hem de ONNX modelinin doğruluğunu değerlendirir.

# Iris_CNBClassifier.py
# The code demonstrates the process of training Complement Naive Bayes (CNB) Classifier model on the Iris dataset, exporting it to ONNX format, and making predictions using the ONNX model. 
# It also evaluates the accuracy of both the original model and the ONNX model.
# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

# import necessary libraries
from sklearn import datasets
from sklearn.naive_bayes import ComplementNB
from sklearn.metrics import accuracy_score, classification_report
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as ort
import numpy as np
from sys import argv

# define the path for saving the model
data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]

# load the Iris dataset
iris = datasets.load_iris()
X = iris.data
y = iris.target

# create a Complement Naive Bayes (CNB) Classifier model
cnb_model = ComplementNB()

# train the model on the entire dataset
cnb_model.fit(X, y)

# predict classes for the entire dataset
y_pred = cnb_model.predict(X)

# evaluate the model's accuracy
accuracy = accuracy_score(y, y_pred)
print("Accuracy of Complement Naive Bayes (CNB) Classifier model:", accuracy)

# display the classification report
print("\nClassification Report:\n", classification_report(y, y_pred))

# define the input data type
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]

# export the model to ONNX format with float data type
onnx_model = convert_sklearn(cnb_model, initial_types=initial_type, target_opset=12)

# save the model to a file
onnx_filename = data_path + "cnb_classifier_iris.onnx"
with open(onnx_filename, "wb") as f:
    f.write(onnx_model.SerializeToString())

# print model path
print(f"Model saved to {onnx_filename}")

# load the ONNX model and make predictions
onnx_session = ort.InferenceSession(onnx_filename)
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name

# display information about input tensors in ONNX
print("\nInformation about input tensors in ONNX:")
for i, input_tensor in enumerate(onnx_session.get_inputs()):
    print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}")

# display information about output tensors in ONNX
print("\nInformation about output tensors in ONNX:")
for i, output_tensor in enumerate(onnx_session.get_outputs()):
    print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}")

# convert data to floating-point format (float32)
X_float32 = X.astype(np.float32)

# predict classes for the entire dataset using ONNX
y_pred_onnx = onnx_session.run([output_name], {input_name: X_float32})[0]

# evaluate the accuracy of the ONNX model
accuracy_onnx = accuracy_score(y, y_pred_onnx)
print("\nAccuracy of Complement Naive Bayes (CNB) Classifier model in ONNX format:", accuracy_onnx)

Çıktı:

Python    Accuracy of Complement Naive Bayes (CNB) Classifier model: 0.6666666666666666
Python    
Python    Classification Report:
Python                   precision    recall  f1-score   support
Python    
Python               0       0.96      1.00      0.98        50
Python               1       0.00      0.00      0.00        50
Python               2       0.51      1.00      0.68        50
Python    
Python        accuracy                           0.67       150
Python       macro avg       0.49      0.67      0.55       150
Python    weighted avg       0.49      0.67      0.55       150
Python    
Python    Model saved to C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Scripts\cnb_classifier_iris.onnx
Python    
Python    Information about input tensors in ONNX:
Python    1. Name: float_input, Data Type: tensor(float), Shape: [None, 4]
Python    
Python    Information about output tensors in ONNX:
Python    1. Name: output_label, Data Type: tensor(int64), Shape: [None]
Python    2. Name: output_probability, Data Type: seq(map(int64,tensor(float))), Shape: []
Python    
Python    Accuracy of Complement Naive Bayes (CNB) Classifier model in ONNX format: 0.6666666666666666


2.20.2. Complement Naive Bayes (CNB) Classifier modeliyle çalışmak için MQL5 kodu

//+------------------------------------------------------------------+
//|                                           Iris_CNBClassifier.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "iris.mqh"
#resource "cnb_classifier_iris.onnx" as const uchar ExtModel[];

//+------------------------------------------------------------------+
//| Test IRIS dataset samples                                        |
//+------------------------------------------------------------------+
bool TestSamples(long model,float &input_data[][4], int &model_classes_id[])
  {
//--- check number of input samples
   ulong batch_size=input_data.Range(0);
   if(batch_size==0)
      return(false);
//--- prepare output array
   ArrayResize(model_classes_id,(int)batch_size);
//---
   float output_data[];
//---
   struct Map
     {
      ulong          key[];
      float          value[];
     } output_data_map[];
//--- check consistency
   bool res=ArrayResize(output_data,(int)batch_size)==batch_size;
//---
   if(res)
     {
      //--- set input shape
      ulong input_shape[]= {batch_size,input_data.Range(1)};
      OnnxSetInputShape(model,0,input_shape);
      //--- set output shapeы
      ulong output_shape1[]= {batch_size};
      ulong output_shape2[]= {batch_size};
      OnnxSetOutputShape(model,0,output_shape1);
      OnnxSetOutputShape(model,1,output_shape2);
      //--- run the model
      res=OnnxRun(model,0,input_data,output_data,output_data_map);
      //--- postprocessing
      if(res)
        {
         //--- postprocessing of sequence map data
         //--- find class with maximum probability
         ulong output_keys[];
         float output_values[];
         //---
         for(uint n=0; n<output_data_map.Size(); n++)
           {
            int model_class_id=-1;
            int max_idx=-1;
            float max_value=-1;
            //--- copy to arrays
            ArrayCopy(output_keys,output_data_map[n].key);
            ArrayCopy(output_values,output_data_map[n].value);
            //ArrayPrint(output_keys);
            //ArrayPrint(output_values);
            //--- find the key with maximum probability
            for(int k=0; k<ArraySize(output_values); k++)
              {
               if(k==0)
                 {
                  max_idx=0;
                  max_value=output_values[max_idx];
                  model_class_id=(int)output_keys[max_idx];
                 }
               else
                 {
                  if(output_values[k]>max_value)
                    {
                     max_idx=k;
                     max_value=output_values[max_idx];
                     model_class_id=(int)output_keys[max_idx];
                    }
                 }
              }
            //--- store the result to the output array
            model_classes_id[n]=model_class_id;
            //Print("model_class_id=",model_class_id);
           }
        }
     }
//---
   return(res);
  }

//+------------------------------------------------------------------+
//| Test all samples from IRIS dataset (150)                         |
//| Here we test all samples with batch=1, sample by sample          |
//+------------------------------------------------------------------+
bool TestAllIrisDataset(const long model,const string model_name,double &model_accuracy)
  {
   sIRISsample iris_samples[];
//--- load dataset from file
   PrepareIrisDataset(iris_samples);
//--- test
   int total_samples=ArraySize(iris_samples);
   if(total_samples==0)
     {
      Print("iris dataset not prepared");
      return(false);
     }
//--- show dataset
   for(int k=0; k<total_samples; k++)
     {
      //PrintFormat("%d (%.2f,%.2f,%.2f,%.2f) class %d (%s)",iris_samples[k].sample_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3],iris_samples[k].class_id,iris_samples[k].class_name);
     }
//--- array for output classes
   int model_output_classes_id[];
//--- check all Iris dataset samples
   int correct_results=0;
   for(int k=0; k<total_samples; k++)
     {
      //--- input array
      float iris_sample_input_data[1][4];
      //--- prepare input data from kth iris sample dataset
      iris_sample_input_data[0][0]=(float)iris_samples[k].features[0];
      iris_sample_input_data[0][1]=(float)iris_samples[k].features[1];
      iris_sample_input_data[0][2]=(float)iris_samples[k].features[2];
      iris_sample_input_data[0][3]=(float)iris_samples[k].features[3];
      //--- run model
      bool res=TestSamples(model,iris_sample_input_data,model_output_classes_id);
      //--- check result
      if(res)
        {
         if(model_output_classes_id[0]==iris_samples[k].class_id)
           {
            correct_results++;
           }
         else
           {
            PrintFormat("model:%s  sample=%d FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f]",model_name,iris_samples[k].sample_id,model_output_classes_id[0],iris_samples[k].class_id,iris_samples[k].features[0],iris_samples[k].features[1],iris_samples[k].features[2],iris_samples[k].features[3]);
           }
        }
     }
   model_accuracy=1.0*correct_results/total_samples;
//---
   PrintFormat("model:%s   correct results: %.2f%%",model_name,100*model_accuracy);
//---
   return(true);
  }

//+------------------------------------------------------------------+
//| Here we test batch execution of the model                        |
//+------------------------------------------------------------------+
bool TestBatchExecution(const long model,const string model_name,double &model_accuracy)
  {
   model_accuracy=0;
//--- array for output classes
   int model_output_classes_id[];
   int correct_results=0;
   int total_results=0;
   bool res=false;

//--- run batch with 3 samples
   float input_data_batch3[3][4]=
     {
        {5.1f,3.5f,1.4f,0.2f}, // iris dataset sample id=1, Iris-setosa
        {6.3f,2.5f,4.9f,1.5f}, // iris dataset sample id=73, Iris-versicolor
        {6.3f,2.7f,4.9f,1.8f}  // iris dataset sample id=124, Iris-virginica
     };
   int correct_classes_batch3[3]= {0,1,2};
//--- run model
   res=TestSamples(model,input_data_batch3,model_output_classes_id);
   if(res)
     {
      //--- check result
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         //--- check result
         if(model_output_classes_id[j]==correct_classes_batch3[j])
            correct_results++;
         else
           {
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch3[j],input_data_batch3[j][0],input_data_batch3[j][1],input_data_batch3[j][2],input_data_batch3[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- run batch with 10 samples
   float input_data_batch10[10][4]=
     {
        {5.5f,3.5f,1.3f,0.2f}, // iris dataset sample id=37 (Iris-setosa)
        {4.9f,3.1f,1.5f,0.1f}, // iris dataset sample id=38 (Iris-setosa)
        {4.4f,3.0f,1.3f,0.2f}, // iris dataset sample id=39 (Iris-setosa)
        {5.0f,3.3f,1.4f,0.2f}, // iris dataset sample id=50 (Iris-setosa)
        {7.0f,3.2f,4.7f,1.4f}, // iris dataset sample id=51 (Iris-versicolor)
        {6.4f,3.2f,4.5f,1.5f}, // iris dataset sample id=52 (Iris-versicolor)
        {6.3f,3.3f,6.0f,2.5f}, // iris dataset sample id=101 (Iris-virginica)
        {5.8f,2.7f,5.1f,1.9f}, // iris dataset sample id=102 (Iris-virginica)
        {7.1f,3.0f,5.9f,2.1f}, // iris dataset sample id=103 (Iris-virginica)
        {6.3f,2.9f,5.6f,1.8f}  // iris dataset sample id=104 (Iris-virginica)
     };
//--- correct classes for all 10 samples in the batch
   int correct_classes_batch10[10]= {0,0,0,0,1,1,2,2,2,2};

//--- run model
   res=TestSamples(model,input_data_batch10,model_output_classes_id);
//--- check result
   if(res)
     {
      for(int j=0; j<ArraySize(model_output_classes_id); j++)
        {
         if(model_output_classes_id[j]==correct_classes_batch10[j])
            correct_results++;
         else
           {
            double f1=input_data_batch10[j][0];
            double f2=input_data_batch10[j][1];
            double f3=input_data_batch10[j][2];
            double f4=input_data_batch10[j][3];
            PrintFormat("model:%s  FAILED [class=%d, true class=%d] features=(%.2f,%.2f,%.2f,%.2f)",model_name,model_output_classes_id[j],correct_classes_batch10[j],input_data_batch10[j][0],input_data_batch10[j][1],input_data_batch10[j][2],input_data_batch10[j][3]);
           }
         total_results++;
        }
     }
   else
      return(false);

//--- calculate accuracy
   model_accuracy=correct_results/total_results;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnStart(void)
  {
   string model_name="CNBClassifier";
//---
   long model=OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(model==INVALID_HANDLE)
     {
      PrintFormat("model_name=%s OnnxCreate error %d for",model_name,GetLastError());
     }
   else
     {
      //--- test all dataset
      double model_accuracy=0;
      //-- test sample by sample execution for all Iris dataset
      if(TestAllIrisDataset(model,model_name,model_accuracy))
         PrintFormat("model=%s all samples accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- test batch execution for several samples
      if(TestBatchExecution(model,model_name,model_accuracy))
         PrintFormat("model=%s batch test accuracy=%f",model_name,model_accuracy);
      else
         PrintFormat("error in testing model=%s ",model_name);
      //--- release model
      OnnxRelease(model);
     }
   return(0);
  }
//+------------------------------------------------------------------+

Çıktı:

Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=51 FAILED [class=2, true class=1] features=(7.00,3.20,4.70,1.40]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=52 FAILED [class=2, true class=1] features=(6.40,3.20,4.50,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=53 FAILED [class=2, true class=1] features=(6.90,3.10,4.90,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=54 FAILED [class=2, true class=1] features=(5.50,2.30,4.00,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=55 FAILED [class=2, true class=1] features=(6.50,2.80,4.60,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=56 FAILED [class=2, true class=1] features=(5.70,2.80,4.50,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=57 FAILED [class=2, true class=1] features=(6.30,3.30,4.70,1.60]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=58 FAILED [class=2, true class=1] features=(4.90,2.40,3.30,1.00]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=59 FAILED [class=2, true class=1] features=(6.60,2.90,4.60,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=60 FAILED [class=2, true class=1] features=(5.20,2.70,3.90,1.40]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=61 FAILED [class=2, true class=1] features=(5.00,2.00,3.50,1.00]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=62 FAILED [class=2, true class=1] features=(5.90,3.00,4.20,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=63 FAILED [class=2, true class=1] features=(6.00,2.20,4.00,1.00]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=64 FAILED [class=2, true class=1] features=(6.10,2.90,4.70,1.40]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=65 FAILED [class=2, true class=1] features=(5.60,2.90,3.60,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=66 FAILED [class=2, true class=1] features=(6.70,3.10,4.40,1.40]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=67 FAILED [class=2, true class=1] features=(5.60,3.00,4.50,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=68 FAILED [class=2, true class=1] features=(5.80,2.70,4.10,1.00]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=69 FAILED [class=2, true class=1] features=(6.20,2.20,4.50,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=70 FAILED [class=2, true class=1] features=(5.60,2.50,3.90,1.10]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=71 FAILED [class=2, true class=1] features=(5.90,3.20,4.80,1.80]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=72 FAILED [class=2, true class=1] features=(6.10,2.80,4.00,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=73 FAILED [class=2, true class=1] features=(6.30,2.50,4.90,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=74 FAILED [class=2, true class=1] features=(6.10,2.80,4.70,1.20]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=75 FAILED [class=2, true class=1] features=(6.40,2.90,4.30,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=76 FAILED [class=2, true class=1] features=(6.60,3.00,4.40,1.40]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=77 FAILED [class=2, true class=1] features=(6.80,2.80,4.80,1.40]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=78 FAILED [class=2, true class=1] features=(6.70,3.00,5.00,1.70]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=79 FAILED [class=2, true class=1] features=(6.00,2.90,4.50,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=80 FAILED [class=0, true class=1] features=(5.70,2.60,3.50,1.00]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=81 FAILED [class=2, true class=1] features=(5.50,2.40,3.80,1.10]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=82 FAILED [class=2, true class=1] features=(5.50,2.40,3.70,1.00]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=83 FAILED [class=2, true class=1] features=(5.80,2.70,3.90,1.20]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=84 FAILED [class=2, true class=1] features=(6.00,2.70,5.10,1.60]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=85 FAILED [class=2, true class=1] features=(5.40,3.00,4.50,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=86 FAILED [class=2, true class=1] features=(6.00,3.40,4.50,1.60]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=87 FAILED [class=2, true class=1] features=(6.70,3.10,4.70,1.50]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=88 FAILED [class=2, true class=1] features=(6.30,2.30,4.40,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=89 FAILED [class=2, true class=1] features=(5.60,3.00,4.10,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=90 FAILED [class=2, true class=1] features=(5.50,2.50,4.00,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=91 FAILED [class=2, true class=1] features=(5.50,2.60,4.40,1.20]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=92 FAILED [class=2, true class=1] features=(6.10,3.00,4.60,1.40]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=93 FAILED [class=2, true class=1] features=(5.80,2.60,4.00,1.20]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=94 FAILED [class=2, true class=1] features=(5.00,2.30,3.30,1.00]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=95 FAILED [class=2, true class=1] features=(5.60,2.70,4.20,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=96 FAILED [class=2, true class=1] features=(5.70,3.00,4.20,1.20]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=97 FAILED [class=2, true class=1] features=(5.70,2.90,4.20,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=98 FAILED [class=2, true class=1] features=(6.20,2.90,4.30,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=99 FAILED [class=0, true class=1] features=(5.10,2.50,3.00,1.10]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier  sample=100 FAILED [class=2, true class=1] features=(5.70,2.80,4.10,1.30]
Iris_CNBClassifier (EURUSD,H1)  model:CNBClassifier   correct results: 66.67%
Iris_CNBClassifier (EURUSD,H1)  model=CNBClassifier all samples accuracy=0.666667