Библиотека H2O: запуск на кластере; обобщенные низкоранговые модели и градиентный бустинг
1. Установка
Сама библиотека H2O написана на Java и может быть скачана и использована в виде готового .jar-файла, если в системе есть JDK. Прямая ссылка на скачивание актуальной на момент написания этого сообщения версии: http://h2o-release.s3.amazonaws.com/h2o/rel-ueno/8/h2o-3.10.4.8.zip. После распаковки можно воспользоваться командойjava -jar h2o.jar
и начать работать с библиотекой при помощи веб-интерфейса Flow, который по умолчанию доступен на http://localhost:54321.Помимо графического веб-интерфейса доступен также R-пакет и Python-библиотека для доступа ко всем функциям H2O. Полный скрипт для установки всех зависимостей есть на http://h2o-release.s3.amazonaws.com/h2o/rel-ueno/8/index.html во вкладке Install in R. Самое главное - нужно не ставить с CRAN, а использовать команду
install.packages("h2o", type = "source",
repos = (c("http://h2o-release.s3.amazonaws.com/h2o/rel-ueno/8/R")))
Тогда будет установлена последняя стабильная версия, и мы сможем избежать проблем с совместимостью при использовании кластеров (об этом ниже).2. Запуск
Запустить библиотеку локально очень просто:library(h2o)
h2o.init(nthreads = 2, # 2 потока
max_mem_size = "2g") # не более 2 Гб ОЗУ
# java version "1.8.0_112"
# Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
# Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
#
# Starting H2O JVM and connecting: .. Connection successful!
#
# R is connected to the H2O cluster:
# H2O cluster uptime: 6 seconds 745 milliseconds
# H2O cluster version: 3.10.4.8
# H2O cluster version age: 13 days
# H2O cluster name: H2O_started_from_R_andrey_lxo832
# H2O cluster total nodes: 1
# H2O cluster total memory: 1.78 GB
# H2O cluster total cores: 4
# H2O cluster allowed cores: 2
# H2O cluster healthy: TRUE
# H2O Connection ip: localhost
# H2O Connection port: 54321
# H2O Connection proxy: NA
# H2O Internal Security: FALSE
# R Version: R version 3.4.0 (2017-04-21)
# Остановка кластера
h2o.shutdown(prompt = FALSE)
При этом работа все равно происходит в режиме клиент-сервер, но и клиентом, и сервером выступает один и тот же ПК.Гораздо интереснее запустить вычисления в распределенном режиме на кластере из нескольких компьютеров. Это можно сделать как поверх Spark-а, так и средствами самой библиотеки H2O (инструкция, также см. http://docs.h2o.ai/h2o/latest-stable/h2o-docs/starting-h2o.html и https://stackoverflow.com/questions/36927443/how-to-connect-another-machine-to-standalone-h2o-installation-to-create-a-cluste). Второй вариант мы и рассмотрим.
Я буду использовать три ПК, соединенных в локальную сеть (теоретически можно даже добавить к локальной сети несколько удаленный серверов, но тогда нужно позаботиться о соответствующей скорости коммуникации с ними): два под управлением Linux и один под управлением Windows. Опытным путем было установлено, что с Linux-машинами узел под Windows дружить не хочет, то есть фактически кластер будет состоять из двух узлов, а третий ПК выступит клиентом.
Прежде всего нужно узнать ip-адреса всех компьютеров и на каждом из них создать одинаковые flat-файлы с перечнем этих адресов и используемых портов. Он может выглядеть, например, так (flatfile.txt):
192.168.1.2:54321
192.168.1.7:54321
192.168.1.8:54321
Кладем этот файл в папку с .jar-файлом H2O, переходим в эту папку и последовательно на обоих узлах выполняем запуск. Общий вид команды:java -Xmx1g -jar h2o.jar -flatfile flatfile.txt -ip 192.168.1.7 -port 54321 -name testh2o -nthreads 2
ip-адрес для каждого ПК нужно указать свой. Опция -Xmx1g
говорит о выделении 1 Гб памяти на каждом узле (объем ОЗУ на всех узлах суммируется - данные делятся между узлами, а не копируются; но при этом все узлы должны иметь равный объем выделенной памяти). -nthreads 2
запускает работу с использованием двух потоков/ядер. Полезно всегда указывать имя создаваемого кластера, в данном случае это testh2o
.Теперь в R на клиентском ПК можно запустить команду
library(h2o)
h2o.init(ip = "192.168.1.7", port = 54321)
# Connection successful!
#
# R is connected to the H2O cluster:
# H2O cluster uptime: 19 seconds 253 milliseconds
# H2O cluster version: 3.10.4.8
# H2O cluster version age: 13 days
# H2O cluster name: testh2o
# H2O cluster total nodes: 2
# H2O cluster total memory: 1.78 GB
# H2O cluster total cores: 4
# H2O cluster allowed cores: 4
# H2O cluster healthy: TRUE
# H2O Connection ip: 192.168.1.7
# H2O Connection port: 54321
# H2O Connection proxy: NA
# H2O Internal Security: FALSE
# R Version: R version 3.4.0 (2017-04-21)
##
## ----------------------------------------------------------------------
##
## Your next step is to start H2O:
## > h2o.init()
##
## For H2O package documentation, ask for help:
## > ??h2o
##
## After starting H2O, you can use the Web UI at http://localhost:54321
## For more information visit http://docs.h2o.ai
##
## ----------------------------------------------------------------------
##
## Attaching package: 'h2o'
## The following objects are masked from 'package:stats':
##
## cor, sd, var
## The following objects are masked from 'package:base':
##
## %*%, %in%, &&, ||, apply, as.factor, as.numeric, colnames,
## colnames<-, ifelse, is.character, is.factor, is.numeric, log,
## log10, log1p, log2, round, signif, trunc
## Connection successful!
##
## R is connected to the H2O cluster:
## H2O cluster uptime: 1 hours 36 minutes
## H2O cluster version: 3.10.4.8
## H2O cluster version age: 13 days
## H2O cluster name: H2O_started_from_R_andrey_afq663
## H2O cluster total nodes: 1
## H2O cluster total memory: 1.66 GB
## H2O cluster total cores: 4
## H2O cluster allowed cores: 3
## H2O cluster healthy: TRUE
## H2O Connection ip: localhost
## H2O Connection port: 54321
## H2O Connection proxy: NA
## H2O Internal Security: FALSE
## R Version: R version 3.4.0 (2017-04-21)
Если версии H2O везде одинаковые, никаких проблем не возникнет.3. Загрузка данных
Будем использовать набор данных MNIST в виде .csv-файла. Сначала загрузим его в R на клиентском ПК:mnist <- data.table::fread("G:/KAGGLE/MNIST/train.csv")
##
Read 0.0% of 42000 rows
Read 71.4% of 42000 rows
Read 42000 rows and 785 (of 785) columns from 0.072 GB file in 00:00:05
Затем отправим на кластер:mnist_h2o <- as.h2o(mnist)
##
|
| | 0%
|
|=================================================================| 100%
mnist_h2o
- ссылка на данные, находящиеся на кластере. Данные на клиенте при необходимости можно удалить. Для загрузки таблицы с кластера обратно на клиент используется функция as.data.frame()
.4. Обобщенные низкоранговые модели
Обобщенные низкоранговые модели (Generalized Low Rank Models) - относительно новый метод понижения размерности и feature engineering-а, способный работать с количественными и категориальными данными, в том числе при наличии пропущенных значений (также позволяет эти пропущенные значения восстанавливать, что особенно полезно). Примеры от разработчиков доступны по ссылке: показана работа с категориальными данными с большим количеством категорий (ZIP-коды). Мы же попробуем применить этот метод к набору данных MNIST, то есть к количественным признакам.fit_glrm <- h2o.glrm(
training_frame = mnist_h2o,
cols = 2:ncol(mnist_h2o),
k = 25,
loss = "Huber",
regularization_x = "L1",
regularization_y = "L1",
max_iterations = 100,
seed = 100)
## Warning in .h2o.startModelJob(algo, params, h2oRestApiVersion): Dropping constant columns: [pixel729, pixel644, pixel645, pixel448, pixel727, pixel728, pixel560, pixel52, pixel760, pixel10, pixel54, pixel53, pixel168, pixel56, pixel11, pixel55, pixel57, pixel16, pixel18, pixel17, pixel19, pixel754, pixel755, pixel756, pixel757, pixel758, pixel759, pixel83, pixel196, pixel82, pixel85, pixel671, pixel84, pixel111, pixel672, pixel112, pixel673, pixel476, pixel392, pixel700, pixel701, pixel141, pixel780, pixel30, pixel781, pixel782, pixel420, pixel783, pixel31, pixel421, pixel140, pixel699, pixel139, pixel8, pixel9, pixel6, pixel7, pixel4, pixel5, pixel2, pixel3, pixel0, pixel21, pixel1, pixel20, pixel23, pixel532, pixel730, pixel22, pixel731, pixel25, pixel24, pixel27, pixel26, pixel29, pixel28].
##
|
| | 0%
|
|= | 1%
|
|= | 2%
|
|== | 3%
|
|=== | 4%
|
|=== | 5%
|
|==== | 6%
|
|==== | 7%
|
|===== | 8%
|
|====== | 9%
|
|====== | 10%
|
|======= | 11%
|
|======== | 12%
|
|======== | 13%
|
|========= | 14%
|
|========== | 15%
|
|========== | 16%
|
|=========== | 17%
|
|=========== | 18%
|
|============ | 19%
|
|============= | 20%
|
|============= | 21%
|
|============== | 22%
|
|=============== | 23%
|
|=============== | 24%
|
|================ | 25%
|
|================= | 25%
|
|================= | 26%
|
|================== | 27%
|
|================== | 28%
|
|=================== | 29%
|
|==================== | 30%
|
|==================== | 31%
|
|===================== | 32%
|
|====================== | 33%
|
|====================== | 34%
|
|======================= | 35%
|
|======================== | 36%
|
|======================== | 37%
|
|========================= | 38%
|
|========================= | 39%
|
|========================== | 40%
|
|=========================== | 41%
|
|=========================== | 42%
|
|============================ | 43%
|
|============================= | 44%
|
|============================= | 45%
|
|============================== | 46%
|
|=============================== | 47%
|
|=============================== | 48%
|
|================================ | 49%
|
|================================ | 50%
|
|================================= | 51%
|
|================================== | 52%
|
|================================== | 53%
|
|=================================== | 54%
|
|==================================== | 55%
|
|==================================== | 56%
|
|===================================== | 57%
|
|====================================== | 58%
|
|====================================== | 59%
|
|======================================= | 60%
|
|======================================== | 61%
|
|======================================== | 62%
|
|========================================= | 63%
|
|========================================= | 64%
|
|========================================== | 65%
|
|=========================================== | 66%
|
|=========================================== | 67%
|
|============================================ | 68%
|
|============================================= | 69%
|
|============================================= | 70%
|
|============================================== | 71%
|
|=============================================== | 72%
|
|=============================================== | 73%
|
|================================================ | 74%
|
|================================================ | 75%
|
|================================================= | 75%
|
|================================================== | 76%
|
|================================================== | 77%
|
|=================================================== | 78%
|
|==================================================== | 79%
|
|==================================================== | 80%
|
|===================================================== | 81%
|
|====================================================== | 82%
|
|====================================================== | 83%
|
|======================================================= | 84%
|
|======================================================= | 85%
|
|======================================================== | 86%
|
|========================================================= | 87%
|
|========================================================= | 88%
|
|========================================================== | 89%
|
|=========================================================== | 90%
|
|=========================================================== | 91%
|
|============================================================ | 92%
|
|============================================================= | 93%
|
|============================================================= | 94%
|
|============================================================== | 95%
|
|============================================================== | 96%
|
|=============================================================== | 97%
|
|================================================================ | 98%
|
|================================================================ | 99%
|
|=================================================================| 100%
plot(fit_glrm)
Получаем интересующие нас признаки, являющиеся сжатым представлением набора данных:
glrm_features <- h2o.getFrame(fit_glrm@model$representation_name)
head(glrm_features)
## Arch1 Arch2 Arch3 Arch4 Arch5
## 1 -0.023838934 -0.0067042793 -0.004798666 -6.710037e-03 0.102796326
## 2 0.452191476 -0.1164057377 -0.010008216 -4.589649e-03 -0.042187363
## 3 0.003063037 -0.0006779755 -0.004529025 5.728521e-05 0.061967327
## 4 -0.009267637 0.0085549730 0.109841063 2.879811e-03 0.004881383
## 5 0.567460535 -0.0901968375 -0.029656044 3.620274e-03 -0.010112527
## 6 0.014677485 -0.0111327070 0.005435568 1.276020e-02 -0.017158013
## Arch6 Arch7 Arch8 Arch9 Arch10
## 1 -0.002049838 -0.011255783 0.0034964740 0.010380343 0.018448194
## 2 0.005293711 0.043573942 0.0061000309 0.131212260 0.067356075
## 3 0.002982732 0.015083789 0.0024269767 -0.001736844 -0.000883601
## 4 0.014332247 0.005040471 0.0005916958 -0.001883092 0.016010417
## 5 -0.005696558 0.020819434 -0.0442964470 0.157357947 0.054486820
## 6 0.022734507 -0.011243639 0.0058288395 0.002825124 -0.038099438
## Arch11 Arch12 Arch13 Arch14 Arch15
## 1 0.001200594 0.007197661 0.0021446493 0.001857507 0.08096261
## 2 0.525883406 -0.033701542 -0.0232480347 0.018670082 -0.03842530
## 3 -0.021079587 -0.011358200 0.0034904765 0.009786409 0.11508169
## 4 0.012919209 -0.011661424 0.0076284178 0.003351322 -0.01107815
## 5 0.489205293 -0.019818808 -0.0333772140 -0.014468126 -0.03416595
## 6 0.158107565 0.043943450 0.0006898032 0.007206788 -0.03082703
## Arch16 Arch17 Arch18 Arch19 Arch20
## 1 -0.003358851 -0.0377203500 0.012996650 -0.0013443249 0.015897515
## 2 -0.035396735 0.0002071116 0.008402813 0.0232244285 -0.021953933
## 3 0.003258883 0.0090865828 0.006932886 -0.0033793350 0.012514092
## 4 -0.001208038 -0.0018296902 -0.007259402 0.0058200663 0.003020545
## 5 -0.038373904 0.0096029611 0.023356840 0.0006823575 -0.018395582
## 6 0.006673400 0.0470293919 -0.019715101 -0.0034832835 -0.004540402
## Arch21 Arch22 Arch23 Arch24 Arch25
## 1 0.008320434 0.0180432932 0.038976883 0.006455668 -0.022873458
## 2 0.038728343 -0.0698869359 -0.053297260 0.143510786 0.029518731
## 3 -0.012342968 -0.0010012054 -0.007652164 0.001941723 0.022512209
## 4 0.011570149 0.0003030875 -0.003557875 -0.009540136 -0.003078434
## 5 0.092758089 -0.0980393480 -0.027618168 0.150369768 -0.025269772
## 6 0.017737585 -0.0347679852 -0.009547614 0.058552958 0.046623420
5. Градиентный бустинг
Теперь применим градиентный бустинг для решения задачи классификации, используя полученные признаки.Объединяем признаки с метками классов:
mnist_glrm <- h2o.cbind(mnist_h2o[, 1], glrm_features)
# Кодируем метку класса как фактор
mnist_glrm[, 1] <- as.factor(mnist_glrm[, 1])
Делим данные на обучающую и тестовую выборки:set.seed(100)
split <- h2o.runif(mnist_glrm)
mnist_train <- mnist_glrm [split <= 0.8,]
mnist_test <- mnist_glrm [split > 0.8,]
Обучаем модель:fit_gbm <- h2o.gbm(
x = 2:26,
y = 1,
training_frame = mnist_train,
model_id = "MNIST",
max_depth = 4,
min_rows = 10,
learn_rate = 0.1,
col_sample_rate = 0.8,
sample_rate = 0.9,
ntrees = 200,
seed = 100)
##
|
| | 0%
|
|= | 2%
|
|== | 4%
|
|==== | 6%
|
|===== | 7%
|
|====== | 9%
|
|======= | 11%
|
|======== | 13%
|
|========== | 15%
|
|=========== | 17%
|
|============ | 19%
|
|============== | 21%
|
|=============== | 23%
|
|================ | 25%
|
|================== | 27%
|
|=================== | 29%
|
|==================== | 31%
|
|===================== | 32%
|
|====================== | 34%
|
|======================== | 36%
|
|========================= | 38%
|
|========================== | 40%
|
|============================ | 42%
|
|============================= | 44%
|
|============================== | 46%
|
|================================ | 49%
|
|================================= | 51%
|
|================================== | 53%
|
|==================================== | 55%
|
|===================================== | 57%
|
|====================================== | 59%
|
|======================================== | 61%
|
|========================================= | 63%
|
|========================================== | 65%
|
|============================================ | 67%
|
|============================================= | 69%
|
|============================================== | 71%
|
|================================================ | 74%
|
|================================================= | 76%
|
|================================================== | 78%
|
|==================================================== | 80%
|
|===================================================== | 82%
|
|====================================================== | 84%
|
|======================================================== | 86%
|
|========================================================= | 88%
|
|========================================================== | 90%
|
|=========================================================== | 92%
|
|============================================================= | 94%
|
|============================================================== | 96%
|
|=============================================================== | 98%
|
|=================================================================| 100%
Качество модели на тестовых данных:h2o.performance(fit_gbm, mnist_test)
## H2OMultinomialMetrics: gbm
##
## Test Set Metrics:
## =====================
##
## MSE: (Extract with `h2o.mse`) 0.06971822
## RMSE: (Extract with `h2o.rmse`) 0.2640421
## Logloss: (Extract with `h2o.logloss`) 0.2386396
## Mean Per-Class Error: 0.0771282
## Confusion Matrix: Extract with `h2o.confusionMatrix(<model>, <data>)`)
## =========================================================================
## Confusion Matrix: vertical: actual; across: predicted
## 0 1 2 3 4 5 6 7 8 9 Error Rate
## 0 823 0 3 2 2 13 6 0 6 1 0.0386 = 33 / 856
## 1 0 935 4 5 1 1 1 1 3 1 0.0179 = 17 / 952
## 2 2 0 787 9 7 5 8 17 9 3 0.0708 = 60 / 847
## 3 2 4 20 759 2 33 2 7 21 11 0.1185 = 102 / 861
## 4 2 2 6 1 769 2 4 6 2 45 0.0834 = 70 / 839
## 5 10 1 5 16 2 708 12 1 9 12 0.0876 = 68 / 776
## 6 9 1 9 1 2 19 790 0 7 0 0.0573 = 48 / 838
## 7 0 6 6 1 4 1 0 822 5 27 0.0573 = 50 / 872
## 8 5 4 15 41 5 12 3 4 784 19 0.1211 = 108 / 892
## 9 0 3 3 19 30 9 0 24 8 712 0.1188 = 96 / 808
## Totals 853 956 858 854 824 803 826 882 854 831 0.0763 = 652 / 8A 541
##
## Hit Ratio Table: Extract with `h2o.hit_ratio_table(<model>, <data>)`
## =======================================================================
## Top-10 Hit Ratios:
## k hit_ratio
## 1 1 0.923662
## 2 2 0.975647
## 3 3 0.988760
## 4 4 0.993795
## 5 5 0.996956
## 6 6 0.998244
## 7 7 0.999063
## 8 8 0.999649
## 9 9 0.999883
## 10 10 1.000000
Если бы мы использовали loss = "Quadratic"
и regularization_x = "None"
, regularization_y = "None"
, получился бы PCA. Результат не впечатляет, хоть он и неплох для не-нейросетевого метода.Полезные ссылки:
- Deep Water - оболочка для создания моделей глубокого обучения с использованием в качестве бэкенда Caffe, Mxnet или Tensorflow (в самой библиотеке H2O глубокое обучение ограничено многослойным перцептроном).
- https://www.h2o.ai/gpu/ - в разработке находится версия H2O, использующая GPU для ускорения вычислений (также ожидается GPU-ускоренная версия data.table).
Было бы логично привести ссылку на файл с данными, для воспроизводимости приведенного в статье кода
ОтветитьУдалитьТак это же классический набор данных, примерно как ирисы. Можно взять здесь: https://www.kaggle.com/c/digit-recognizer
ОтветитьУдалить