Документация Engee
Notebook

Сравнение производительности ансамблевых методов Julia и Matlab

Введение

Современные задачи машинного обучения требуют не только высокой точности моделей, но и эффективного использования вычислительных ресурсов. Выбор инструментария напрямую влияет на скорость разработки и время обучения, что особенно критично при работе с большими объёмами данных и ансамблевыми методами, известными своей ресурсоёмкостью.

Ансамблевые методы — это методы машинного обучения, которые объединяют несколько базовых моделей (например, деревья решений) для получения более точного и устойчивого прогноза, чем каждая модель по отдельности.

В данном примере представлен сравнительный анализ трёх подходов к обучению модели классификации на основе случайного леса:

  • с использованием библиотек MLJ и DecisionTree на Julia,
  • а также функции fitcensemble в подключаемом ядре Matlab.

Все методы решают одну и ту же задачу бинарной классификации на синтетических данных, что позволяет объективно сопоставить их производительность.

Импорт библиотек

Присоединим необходимые библиотеки.

In [ ]:
import Pkg 
Pkg.add(["Random", "Distributions", "LinearAlgebra", "Statistics", "DecisionTree", "MLJ", "MLJDecisionTreeInterface"])
using Random, Distributions, LinearAlgebra, Statistics

Генерация данных

Создадим десять красных и десять синих базовых точек. Обратите внимание, в Julia вы можете использовать символы эмодзи в именах переменных.

In [ ]:
🔴 = rand(MvNormal([0.0, 1.0], 1.0I), 10)'
🔵 = rand(MvNormal([1.0, 0.0], 1.0I), 10)' 
Warning: detected a stack overflow; program state may be corrupted, so further execution might be unreliable.
Out[0]:
10×2 adjoint(::Matrix{Float64}) with eltype Float64:
  1.68076   -0.39267
 -1.04332   -0.524557
  0.403396   0.711854
  1.40658    0.840808
 -0.271765   0.203544
  0.706984   0.700587
  2.65888    0.695686
 -0.822003  -0.871902
  0.170193  -0.256672
  0.884981  -0.725199

Отобразим базовые точки на координатной плоскости.

In [ ]:
gr()
график1 = scatter(🔴[:, 1], 🔴[:, 2], color=:red, marker=:circle, label="Красные", legend=:topright)
scatter!(🔵[:, 1], 🔵[:, 2], color=:blue, marker=:circle, label="Синие")
display(график1)
No description has been provided for this image

Создадим по 50000 точек каждого цвета с центром в случайных базовых точках.

In [ ]:
N = 50000

🔴 = 🔴[rand(1:10, N), :] + randn(N, 2) .* sqrt(0.02)
🔵 = 🔵[rand(1:10, N), :] + randn(N, 2) .* sqrt(0.02)

график2  =scatter(🔴[:, 1], 🔴[:, 2], color=:red, marker=:circle, markersize=1, label="Красные", alpha=0.36, legend=:topright)
scatter!(🔵[:, 1], 🔵[:, 2], color=:blue, marker=:circle, markersize=1, label="Синие", alpha=0.36)
display(график2)
No description has been provided for this image

Объединим данные и создадим метки классов для задачи классификации. Создадим единичный вектор меток и присвоим метку -1 для синих точек.

In [ ]:
данные = [🔴; 🔵] 
метки = ones(2*N) 
метки[N+1:2*N] .= -1
# красные 1, синие -1 
display(данные)
100000×2 Matrix{Float64}:
 -1.17727     0.706835
 -1.57707     0.774681
  0.178602   -1.29926
 -1.01894     1.71275
 -0.0370812  -0.457162
  0.0653013  -0.420637
 -1.09482     1.26002
 -1.60749     0.494051
  0.410089    0.599331
  0.186491   -1.19344
 -0.91909     0.618676
 -1.10581     1.17909
  0.0183241   2.10268
  ⋮          
  0.430693    0.724032
  1.72878    -0.155705
 -1.02294    -0.301795
 -0.722527   -0.963421
  0.0536655  -0.328961
  1.5339     -0.571084
  0.865277   -0.797651
  2.67771     0.722167
 -0.971874   -0.562102
 -0.630223   -0.546642
 -0.179057    0.319442
  0.231351    0.864316

Сравнение моделей классификации

MLJ

Выполним обучение модели с помощью инструментов библиотеки MLJ (Machine Learning in Julia).

In [ ]:
using MLJ, MLJDecisionTreeInterface
дерево = @load DecisionTreeClassifier pkg=DecisionTree
время = @elapsed begin
   модель =  MLJ.fit!(machine(EnsembleModel(model = дерево(max_depth=-1), n=100, bagging_fraction=1.0, rng=1234), 
    DataFrame(данные, :auto), coerce(ifelse.(метки .== 1.0, 1, 2), Multiclass)))
end

display(модель)
println("Время обучения: ", время, " секунд")
[ Info: For silent loading, specify `verbosity=0`. 
[ Info: Training machine(ProbabilisticEnsembleModel(model = DecisionTreeClassifier(max_depth = -1, …), …), …).

import MLJDecisionTreeInterface ✔
Training ensemble:   3%[=>                                                ]  ETA: 0:00:22
Training ensemble:   5%[==>                                               ]  ETA: 0:00:25
Training ensemble:   7%[===>                                              ]  ETA: 0:00:27
Training ensemble:   8%[====>                                             ]  ETA: 0:00:44
Training ensemble:  10%[=====>                                            ]  ETA: 0:00:40
Training ensemble:  12%[======>                                           ]  ETA: 0:00:37
Training ensemble:  14%[=======>                                          ]  ETA: 0:00:35
Training ensemble:  16%[========>                                         ]  ETA: 0:00:33
Training ensemble:  18%[=========>                                        ]  ETA: 0:00:31
Training ensemble:  20%[==========>                                       ]  ETA: 0:00:30
Training ensemble:  22%[===========>                                      ]  ETA: 0:00:28
Training ensemble:  24%[============>                                     ]  ETA: 0:00:27
Training ensemble:  26%[=============>                                    ]  ETA: 0:00:26
Training ensemble:  28%[==============>                                   ]  ETA: 0:00:25
Training ensemble:  30%[===============>                                  ]  ETA: 0:00:24
Training ensemble:  32%[================>                                 ]  ETA: 0:00:24
Training ensemble:  34%[=================>                                ]  ETA: 0:00:23
Training ensemble:  36%[==================>                               ]  ETA: 0:00:22
Training ensemble:  38%[===================>                              ]  ETA: 0:00:21
Training ensemble:  40%[====================>                             ]  ETA: 0:00:21
Training ensemble:  42%[=====================>                            ]  ETA: 0:00:20
Training ensemble:  44%[======================>                           ]  ETA: 0:00:19
Training ensemble:  46%[=======================>                          ]  ETA: 0:00:19
Training ensemble:  48%[========================>                         ]  ETA: 0:00:18
Training ensemble:  50%[=========================>                        ]  ETA: 0:00:17
Training ensemble:  52%[==========================>                       ]  ETA: 0:00:16
Training ensemble:  54%[===========================>                      ]  ETA: 0:00:16
Training ensemble:  56%[============================>                     ]  ETA: 0:00:15
Training ensemble:  58%[=============================>                    ]  ETA: 0:00:14
Training ensemble:  60%[==============================>                   ]  ETA: 0:00:13
Training ensemble:  62%[===============================>                  ]  ETA: 0:00:13
Training ensemble:  64%[================================>                 ]  ETA: 0:00:12
Training ensemble:  66%[=================================>                ]  ETA: 0:00:11
Training ensemble:  68%[==================================>               ]  ETA: 0:00:10
Training ensemble:  70%[===================================>              ]  ETA: 0:00:10
Training ensemble:  72%[====================================>             ]  ETA: 0:00:09
Training ensemble:  74%[=====================================>            ]  ETA: 0:00:08
Training ensemble:  76%[======================================>           ]  ETA: 0:00:08
Training ensemble:  78%[=======================================>          ]  ETA: 0:00:07
Training ensemble:  80%[========================================>         ]  ETA: 0:00:07
Training ensemble:  82%[=========================================>        ]  ETA: 0:00:06
Training ensemble:  84%[==========================================>       ]  ETA: 0:00:05
Training ensemble:  86%[===========================================>      ]  ETA: 0:00:05
Training ensemble:  88%[============================================>     ]  ETA: 0:00:04
Training ensemble:  90%[=============================================>    ]  ETA: 0:00:03
Training ensemble:  92%[==============================================>   ]  ETA: 0:00:03
Training ensemble:  94%[===============================================>  ]  ETA: 0:00:02
Training ensemble:  96%[================================================> ]  ETA: 0:00:01
Training ensemble:  98%[=================================================>]  ETA: 0:00:01
Training ensemble: 100%[==================================================] Time: 0:00:31

trained Machine; caches model-specific representations of data
  model: ProbabilisticEnsembleModel(model = DecisionTreeClassifier(max_depth = -1, …), …)
  args: 
    1:	Source @591 ⏎ Table{AbstractVector{ScientificTypesBase.Continuous}}
    2:	Source @049 ⏎ AbstractVector{Multiclass{2}}
Время обучения: 33.510742957 секунд

Время обучения модели с помощью MLJ составило: 33.51 секунд.

Matlab fitensemble

Выполним обучение модели внутри ядра Matlab с помощью функции fitcensemble, и измерим время выполнения.

In [ ]:
using MATLAB

cdata = данные
grp = метки
@mput cdata grp N

mat"""
tic
mdl = fitcensemble(cdata, grp, 'Method', 'Bag');
stime = toc;
disp(mdl)
"""
@mget(stime)
println("Время обучения: ", stime, " секунд")
Warning: detected a stack overflow; program state may be corrupted, so further execution might be unreliable.
>> >> >> >> >> >>   ClassificationBaggedEnsemble
             ResponseName: 'Y'
    CategoricalPredictors: []
               ClassNames: [-1 1]
           ScoreTransform: 'none'
          NumObservations: 100000
               NumTrained: 100
                   Method: 'Bag'
             LearnerNames: {'Tree'}
     ReasonForTermination: 'Terminated normally after completing the requested number of training cycles.'
                  FitInfo: []
       FitInfoDescription: 'None'
                FResample: 1
                  Replace: 1
         UseObsForLearner: [100000x100 logical]


Время обучения: 29.569731 секунд

Время обучения модели с помощью Matlab составило: 29.57 секунд.

DecisionTree

Выполним обучение модели с помощью инструментов библиотеки DecisionTree.

In [ ]:
using DecisionTree
время = @elapsed begin
модель = build_forest(метки, данные, 2, 100, 1.0, rng=Random.GLOBAL_RNG)
end
display(модель)
println("Время обучения: ", время, " секунд")
Ensemble of Decision Trees
Trees:      100
Avg Leaves: 2290.95
Avg Depth:  30.27
Время обучения: 6.06898517 секунд

Время обучения модели с помощью DecisionTree составило: 6.07 секунд. Это наилучший результат из исследуемых.

Заключение

В данном исследовании проведено обучение ансамбля из 100 решающих деревьев на синтетических данных. Сравнение трёх подходов показало существенную разницу в производительности.
Наилучшую производительность продемонстрировала нативная библиотека Julia DecisionTree (6.07 с), что делает её отличным выбором для высоконагруженных задач и прототипирования.
Результаты подтверждают, что Engee обеспечивает значительный прирост производительности по сравнению с Matlab, сохраняя при этом совместимость с его синтаксисом. Представленные методы классификации применимы в задачах компьютерного зрения, предиктивной аналитики, медицинской диагностики и финансового моделирования, где требуется высокая точность и скорость обработки больших объёмов информации.