Не любите Java? Да вы не умеете ее готовить! Mani Sarkar предлагает нам познакомиться с инструментом Valohai, позволяющим проводить исследования модели на Java.
Введение
Некоторое время назад я столкнулся с облачным сервисом под названием Valohai, и меня порадовал его пользовательский интерфейс и простота дизайна и компоновки. Я попросил об услуге одного из членов Valohai и получил демо-версию. До этого я написал простой конвейер с использованием GNU Parallel, JavaScript, Python и Bash — и еще один, использующий только GNU Parallel и Bash.
Я также думал об использовании готовых к использованию инструментов управления задачами / рабочими процессами, таких как Jenkins X, Jenkins Pipeline, Concourse или Airflow, но по разным причинам я решил этого не делать.
Я заметил, что многие примеры и документация по Valohai основаны на Python и R и соответствующих фреймворках и библиотеках. Я решил не упускать возможность и хочу исправить нехватку примеров и документации.
Valohai подтолкнул меня к тому, чтобы реализовать что-то, используя известную библиотеку Java под названием DL4J — Deep Learning for Java.
Мой первый опыт работы с Valohai уже произвел на меня хорошее впечатление после прощупывания его дизайна, компоновки и рабочего процесса. Создатели уже приняли во внимание различные аспекты как рабочих процессов разработчика, так и инфраструктуры. В нашем мире процесс разработки инфраструктуры в основном управляется командами DevOps или SysOps, и мы знаем нюансы и болевые точки, связанные с ним.
Что нам нужно и как?
В любом проекте по машинному обучению есть два важных компонента (с точки зрения высокого уровня) — это код, который будет работать с моделью, и код, который будет работать с инфраструктурой, в которой будет выполняться весь жизненный цикл проекта.
Конечно, будут шаги и компоненты, необходимые до, во время и после, но для простоты, скажем, нам нужен код и инфраструктура.
Код
Для кода я выбрал сложный пример с использованием DL4J, это проект MNist с обучающим набором из 60000 изображений и тестовым набором из 10000 изображений рукописных цифр. Этот набор данных доступен через библиотеку DL4J (точно так же, как и Keras).
Прежде чем начать, рекомендуется взглянуть на исходный код, который мы будем использовать. Основной класс Java называется org.deeplearning4j.feedforward.mnist.MLPMnistSingleLayerRunner.
Инфраструктура
Мы решили попробовать пример Java с использованием Valohai в качестве нашей инфраструктуры для проведения экспериментов (обучение и оценка модели). Valohai распознает git-репозитории и напрямую подключается к ним, позволяя выполнять наш код независимо от платформы или языка — так что мы увидим, как это работает. Это также означает, что если вы используете GitOps или Infrastructure-As-Code, у вас также все будет работать.
Для этого нам просто нужна учетная запись в Valohai. После создания бесплатной учетной записи получаем доступ к нескольким экземплярам различных конфигураций. Для того, что мы хотели бы сделать, Free-Tier более чем достаточно.
Deep Learning для Java и Valohai
Мы предоставим все зависимости в образ Docker и будем использовать его для компиляции нашего Java-приложения, обучения модели и оценки ее на платформе Valohai с помощью простого файла valohai.yaml, который находится в корневой папке репозитория проекта.
Deep Learning для Java: DL4J
Самая простая часть. Нам не нужно много делать, просто соберите jar и загрузите набор данных в контейнер Docker. У нас есть предварительно созданный образ Docker, который содержит все зависимости, необходимые для создания приложения Java. Мы поместили этот образ в Docker Hub, и вы можете найти его, выполнив поиск dl4j-mnist-single-layer (мы будем использовать специальный тег, как определено в файле YAML). Мы решили использовать GraalVM 19.1.1 в качестве нашей сборочной и выполняемой среды Java для этого проекта, и она встроена в образ Docker.
Когда uber jar вызывается из командной строки, мы создаем класс MLPMnistSingleLayerRunner, который указывает нам предполагаемое действие в зависимости от параметров, передаваемых в:
public static void main(String[] args) throws Exception {
MLPMnistSingleLayerRunner mlpMnistRunner = new MLPMnistSingleLayerRunner();
JCommander.newBuilder()
.addObject(mlpMnistRunner)
.build()
.parse(args);
mlpMnistRunner.execute();
}
Параметры, переданные в uber jar, принимаются этим классом и обрабатываются методом execute().
Мы можем создать модель с помощью параметра --action train и оценить созданную модель с помощью параметра --action evaluate переданного в приложение Java.
Основные части приложения Java, которое выполняет эту работу, можно найти в двух классах Java, упомянутых в разделах ниже.
Обучение модели
Вызовем
./runMLPMnist.sh --action train --output-dir ${VH_OUTPUTS_DIR}
or
java -Djava.library.path=""
-jar target/MLPMnist-1.0.0-bin.jar
--action train --output-dir ${VH_OUTPUTS_DIR}
Эта команда создает модель с именем mlpmnist-single-layer.pb в папке, указанной параметром --output-dir переданным в начале выполнения. С точки зрения Valohai, он должен быть помещен в $ {VH_OUTPUTS_DIR}, что мы и делаем (см. файл valohai.yaml).
Исходный код см. в классе MLPMNistSingleLayerTrain.java.
Оценка модели
Вызовем
./runMLPMnist.sh --action evaluate --input-dir ${VH_INPUTS_DIR}/model
or
java -Djava.library.path=""
-jar target/MLPMnist-1.0.0-bin.jar
--action evaluate --input-dir ${VH_INPUTS_DIR}/model
Предполагается, что модель (созданная на этапе обучения) с именем mlpmnist-single-layer.pb будет присутствовать в папке, указанной в параметре --input-dir переданном при вызове приложения.
Исходный код см. в классе MLPMNistSingleLayerEvaluate.java.
Я надеюсь, что эта короткая иллюстрация прояснит, как работает приложение Java, которое обучает и оценивает модель.
Это все, что от нас требуется, но не стесняйтесь поиграть с остальными исходниками (вместе с README.md и скриптами bash) и удовлетворить свое любопытство и понимание того, как это делается!
Valohai
Valohai позволяет нам свободно связывать нашу среду выполнения, код и набор данных, как вы можете видеть из структуры файла YAML ниже. Таким образом, различные компоненты могут развиваться независимо друг от друга. Следовательно, в наш контейнер Docker упакованы только компоненты сборки и рантайма.
Во время выполнения мы собираем Uber JAR в контейнере Docker, загружаем его в какое-либо внутреннее или внешнее хранилище, а затем с помощью другого шага выполнения загружаем Uber JAR и набор данных из хранилища (или другого места) для запуска обучения. Таким образом, два шага выполнения разъединяются; например, мы можем скомпилировать jar один раз и выполнить сотни тренировочных шагов на одном jar. Поскольку среды сборки и среды выполнения не должны изменяться так часто, мы можем их кэшировать, а код, набор данных и модели могут быть динамически доступны во время выполнения.
valohai.yaml
Главной частью интеграции нашего Java-проекта с инфраструктурой Valohai является определение порядка шагов Execution в файле valohai.yaml, расположенном в корне папки вашего проекта. Наш valohai.yaml выглядит так:
---
- step:
name: Build-dl4j-mnist-single-layer-java-app
image: neomatrix369/dl4j-mnist-single-layer:v0.5
command:
- cd ${VH_REPOSITORY_DIR}
- ./buildUberJar.sh
- echo "~~~ Copying the build jar file into ${VH_OUTPUTS_DIR}"
- cp target/MLPMnist-1.0.0-bin.jar ${VH_OUTPUTS_DIR}/MLPMnist-1.0.0.jar
- ls -lash ${VH_OUTPUTS_DIR}
environment: aws-eu-west-1-g2-2xlarge
- step:
name: Run-dl4j-mnist-single-layer-train-model
image: neomatrix369/dl4j-mnist-single-layer:v0.5
command:
- echo "~~~ Unpack the MNist dataset into ${HOME} folder"
- tar xvzf ${VH_INPUTS_DIR}/dataset/mlp-mnist-dataset.tgz -C ${HOME}
- cd ${VH_REPOSITORY_DIR}
- echo "~~~ Copying the build jar file from ${VH_INPUTS_DIR} to current location"
- cp ${VH_INPUTS_DIR}/dl4j-java-app/MLPMnist-1.0.0.jar .
- echo "~~~ Run the DL4J app to train model based on the the MNist dataset"
- ./runMLPMnist.sh {parameters}
inputs:
- name: dl4j-java-app
description: DL4J Java app file (jar) generated in the previous step 'Build-dl4j-mnist-single-layer-java-app'
- name: dataset
default: https://github.com/neomatrix369/awesome-ai-ml-dl/releases/download/mnist-dataset-v0.1/mlp-mnist-dataset.tgz
description: MNist dataset needed to train the model
parameters:
- name: --action
pass-as: '--action {v}'
type: string
default: train
description: Action to perform i.e. train or evaluate
- name: --output-dir
pass-as: '--output-dir {v}'
type: string
default: /valohai/outputs/
description: Output directory where the model will be created, best to pick the Valohai output directory
environment: aws-eu-west-1-g2-2xlarge
- step:
name: Run-dl4j-mnist-single-layer-evaluate-model
image: neomatrix369/dl4j-mnist-single-layer:v0.5
command:
- cd ${VH_REPOSITORY_DIR}
- echo "~~~ Copying the build jar file from ${VH_INPUTS_DIR} to current location"
- cp ${VH_INPUTS_DIR}/dl4j-java-app/MLPMnist-1.0.0.jar .
- echo "~~~ Run the DL4J app to evaluate the trained MNist model"
- ./runMLPMnist.sh {parameters}
inputs:
- name: dl4j-java-app
description: DL4J Java app file (jar) generated in the previous step 'Build-dl4j-mnist-single-layer-java-app'
- name: model
description: Model file generated in the previous step 'Run-dl4j-mnist-single-layer-train-model'
parameters:
- name: --action
pass-as: '--action {v}'
type: string
default: evaluate
description: Action to perform i.e. train or evaluate
- name: --input-dir
pass-as: '--input-dir {v}'
type: string
default: /valohai/inputs/model
description: Input directory where the model created by the previous step can be found created
environment: aws-eu-west-1-g2-2xlarge
Как работает Build-dl4j-mnist-single-layer-java-app
Из файла YAML мы видим, что мы определяем этот шаг, сначала используя образ Docker, а затем запускаем скрипт для сборки Uber JAR. Наш образ докера имеет настройку зависимостей среды сборки (например, GraalVM JDK, Maven и т. д.) для создания приложения Java. Мы не указываем какие-либо входные данные или параметры, так как это этап сборки. Как только сборка будет успешной, мы копируем uber jar с именем MLPMnist-1.0.0-bin.jar (оригинальное имя) в папку /valohai/outputs (представленную как ${VH_OUTPUTS_DIR} ). Все в этой папке автоматически сохраняется в хранилище вашего проекта, например, в корзине AWS S3. Наконец, мы определяем нашу работу для работы в среде AWS.
Как работает Run-dl4j-mnist-single-layer-train-model
Семантика определения аналогична предыдущему шагу, за исключением того, что мы указываем два ввода: один для uber jar ( MLPMnist-1.0.0.jar ), а другой — для набора данных (распаковывается в папку ${HOME}/.deeplearning4j ). Мы будем передавать два параметра — --action train и --output-dir /valohai/outputs. Модель, созданная на этом шаге, собирается в /valohai/outputs/model (представлена в виде ${VH_OUTPUTS_DIR}/model ).
Как работает Run-dl4j-mnist-single-layer -valu-model
Опять же, этот шаг аналогичен предыдущему шагу, за исключением того, что мы будем передавать два параметра --action evaluate и --input-dir /valohai/inputs/model. Кроме того, мы снова указали в вводе: разделы, определенные в файле YAML с именем dl4j-java-app и model без заданного по умолчанию для них обоих. Это позволит нам выбрать uber jar и модель, которую мы хотим оценить — которая была создана с помощью шага Run-dl4j-mnist-single-layer-train-model, используя веб-интерфейс.
Я надеюсь, что это объясняет шаги в приведенном выше файле определения, но если вам требуется дополнительная помощь, пожалуйста, не стесняйтесь просматривать документацию и туториалы.
Веб-интерфейс Valohai
Получив учетную запись, мы можем войти и продолжить создание проекта с именем mlpmnist-single-layer и связать git repo github.com/valohai/mlpmnist-dl4j-example с проектом и сохранить проект.
Теперь вы можете выполнить шаг и посмотреть, как это получится!
Сборка Java-приложения DL4J
Перейдите на вкладку «Execution» в веб-интерфейсе и либо скопируйте существующее execution, либо создайте новое с помощью кнопки [Create execution]. Все необходимые параметры по умолчанию будут заполнены. Выберите Step Build-dl4j-mnist-single-layer-java-app.
Для Окружения я выбрал AWS eu-west-1 g2.2xlarge и щелкнул по кнопке [Create execution] внизу страницы, чтобы увидеть начало выполнения.
Обучение модели
Перейдите на вкладку «Execution» в веб-интерфейсе и сделайте то же, что и на предыдущем шаге, и выберите Run-dl4j-mnist-single-layer-train-model. Вам нужно будет выбрать приложение Java (просто введите jar в поле), созданное на предыдущем шаге. Набор данных уже был предварительно заполнен с помощью файла valohai.yaml:
Нажмите [Create Execution], чтобы начать.
Вы увидите результат в консоли:
[<--- snipped --->]
11:17:05 =======================================================================
11:17:05 LayerName (LayerType) nIn,nOut TotalParams ParamsShape
11:17:05 =======================================================================
11:17:05 layer0 (DenseLayer) 784,1000 785000 W:{784,1000}, b:{1,1000}
11:17:05 layer1 (OutputLayer) 1000,10 10010 W:{1000,10}, b:{1,10}
11:17:05 -----------------------------------------------------------------------
11:17:05 Total Parameters: 795010
11:17:05 Trainable Parameters: 795010
11:17:05 Frozen Parameters: 0
11:17:05 =======================================================================
[<--- snipped --->]
Созданные модели можно найти на вкладке «Outputs» главной вкладки «Execution» во время и после выполнения:
Вы могли заметить несколько артефактов во вложенной вкладке Outputs. Это потому, что мы сохраняем контрольные точки в конце каждой эпохи. Посмотрим на это в логах:
[<--- snipped --->]
11:17:14 o.d.o.l.CheckpointListener - Model checkpoint saved: epoch 0, iteration 469, path: /valohai/outputs/checkpoint_0_MultiLayerNetwork.zip
[<--- snipped --->]
Чекпоинт содержит состояние модели в трех файлах:
configuration.json
coefficients.bin
updaterState.bin
Обучение модели. Метаданные
Возможно, вы заметили эти записи в журналах выполнения:
[<--- snipped --->]
11:17:05 {"epoch": 0, "iteration": 0, "score (loss function)": 2.410047}
11:17:07 {"epoch": 0, "iteration": 100, "score (loss function)": 0.613774}
11:17:09 {"epoch": 0, "iteration": 200, "score (loss function)": 0.528494}
11:17:11 {"epoch": 0, "iteration": 300, "score (loss function)": 0.400291}
11:17:13 {"epoch": 0, "iteration": 400, "score (loss function)": 0.357800}
11:17:14 o.d.o.l.CheckpointListener - Model checkpoint saved: epoch 0, iteration 469, path: /valohai/outputs/checkpoint_0_MultiLayerNetwork.zip
[<--- snipped --->]
Эти данные позволяют Valohai получить эти значения (в формате JSON), которые будут использоваться для построения метрики, которые можно увидеть во время и после выполнения на дополнительной вкладке «Metadata» на главной вкладке «Executions»:
Мы смогли сделать это, подключив класс ValohaiMetadataCreator к модели, так что во время обучения Valohai обращается к этому классу. В случае этого класса мы выводим несколько эпох, количество итераций и Score (значение функции loss). Вот фрагмент кода из класса:
public void iterationDone(Model model, int iteration, int epoch) {
if (printIterations <= 0)
printIterations = 1;
if (iteration % printIterations == 0) {
double score = model.score();
System.out.println(String.format(
"{"epoch": %d, "iteration": %d, "score (loss function)": %f}",
epoch,
iteration,
score)
);
}
}
Оценка модели
Как только модель была успешно создана на предыдущем этапе, следует ее оценить. Мы создаем новое Execution точно так же, как и ранее, но на этот раз выбираем шаг Run-dl4j-mnist-single-layer -valu-model. Нам нужно будет снова выбрать приложение Java (MLPMnist-1.0.0.jar) и созданную модель (mlpmnist-single-layer.pb), прежде чем начинать выполнение (как показано ниже):
После выбора нужной модели в качестве входных данных нажмите кнопку [Create execution]. Оно быстрее исполнится, чем предыдущее, и мы увидим следующий результат:
Мы видим, что наш «hello world» привел к получению модели, точность которой составляет около 97% на основе тестового набора данных. Confusion matrix помогает найти случаи, когда цифра была неправильно предсказана как другая цифра.
Остается вопрос (и выходящий за рамки этого поста) — насколько хороша модель, когда сталкиваешься с реальными данными?
Чтобы клонировать репозиторий git, то вот что нужно сделать:
$ git clone https://github.com/valohai/mlpmnist-dl4j-example
Затем нам нужно связать наш проект Valohai, созданный через веб-интерфейс в приведенном выше разделе, с проектом, хранящимся на нашей локальной машине (тот, который мы только что клонировали). Выполните следующие команды, чтобы сделать это:
$ cd mlpmnist-dl4j-example
$ vh project --help ### to see all the project-specific options we have for Valohai
$ vh project link
Вам будет показано что-то вроде этого:
[ 1] mlpmnist-single-layer
...
Which project would you like to link with /path/to/mlpmnist-dl4j-example?
Enter [n] to create a new project.:
Выберите 1 (или подходящий вам вариант), и вы должны увидеть это сообщение:
Success! Linked /path/to/mlpmnist-dl4j-example to mlpmnist-single-layer.
Еще кое-что, прежде чем идти дальше, убедитесь, что ваш проект Valohai синхронизирован с последним git-проектом, выполнив это:
$ vh project fetch
Теперь мы можем выполнить шаги из CLI с помощью:
$ vh exec run Build-dl4j-mnist-single-layer-java-app
После того, как Execution выполнено, мы можем проверить его с помощью:
$ vh exec info
$ vh exec logs
$ vh exec watch
Заключение
Как мы видели, очень удобно работать с DL4J и Valohai вместе. Кроме того, мы можем разрабатывать различные компоненты, из которых состоят наши эксперименты (исследования), то есть среду сборки / выполнения, код и набор данных, и интегрировать их в наш проект.
Примеры шаблонов, использованные в этом посте, — хороший способ начать создавать более сложные проекты. И вы можете использовать веб-интерфейс или интерфейс командной строки, чтобы выполнить свою работу с Valohai. С CLI вы также можете интегрировать его с вашими установками и сценариями (или даже с заданиями CRON или CI / CD).
Кроме того, ясно, что если я работаю над проектом, связанным с AI / ML / DL, мне не нужно заботиться о создании и поддержке сквозного конвейера (что пришлось сделать многим другим и мне в прошлом).
Ссылки
- Проект mlpmnist-dl4j-examples на GitHub
- Потрясающие ресурсы AI / ML / DL
- Ресурсы Java AI / ML / DL
- Deep Learning и ресурсы DL4J
Спасибо за внимание!
Автор: WhiteBlackGoose