Начните использовать платформу машинного обучения независимо от того, есть ли у вас кластер
В этом посте демонстрируется пример переноса исследовательского кода машинного обучения в рабочую среду и развертывания эффективной, воспроизводимой и устойчивой среды для обучения сотен моделей.
Мой репозиторий GitHub «kubeflow_k8s» содержит все файлы python и yaml, а также инструкции по установке, необходимые для получения продемонстрированных здесь результатов.
Пример обучения моделиtrain_amazon.py подготавливает текстовые обучающие данные, загружает и совершенствует модель текстовой тональности TensorFlow и выполняет ее вывод для проверки текстовых данных — и все это за один запуск:
python3 train_amazon.py
Цель – создать рабочую среду:
Вот основные шаги.
Кластер
Репозиторий GitHub «Kubeflow_k8s» подробно описывает пошаговый процесс установки и развертывания кластера Kubeflow/Kubernetes на настольном компьютере, проверенный на моей Fedora/32-Core/130 Gib. и Macbook Pro mini/2 ядра/8 Гб.
Рефакторинг в постоянные функциональные компонентыtrain_amazon_refactured.py иллюстрирует разделение train_amazon.py на функциональные блоки без сохранения состояния, которые сохраняют его результаты. Например:
def get_model(output_untrained_model: str): hub_layer = hub.KerasLayer( "https://tfhub.dev/google/tf2-preview/nnlm-en-dim128/1", output_shape = [128], input_shape = [], dtype = tf.string, name = 'input', trainable = False ) model = tf.keras.Sequential() model.add(hub_layer) model.add(tf.keras.layers.Dense(64, activation = 'relu')) model.add(tf.keras.layers.Dense(3, activation = 'softmax', name = 'output')) model.compile( loss = 'categorical_crossentropy', optimizer = 'Adam', metrics = ['accuracy'] ) model.summary() print("\n\nsave untrained_model.pickle\n\n") model.save(output_untrained_model)
Функция get_model загружает обученную модель nnlm-en-dim128, добавляет два полносвязных слоя, определяет слой классификатора с тремя классами и сохраняет необученную модель. Убедитесь, что новые выходные данные не изменились после рефакторинга:
python3 train_amazon_refactured.py
Контейнеризация в компоненты и конвейер Kubeflow
kfp_train_amazon.py определяет четыре компонента и конвейер. Сравните новый рецепт контейнера get_model (который под капотом предписывает локальный образ докера и сборку компонентов через декоратор Kubeflow) с предыдущим функциональным компонентом:
@component( packages_to_install = ["tensorflow", "tensorflow_hub"], output_component_file = "component_nnlm_model.yaml" ) def nnlm_model_download(untrained_model: Output[Artifact]): import tensorflow as tf import tensorflow_hub as hub hub_layer = hub.KerasLayer( "https://tfhub.dev/google/tf2-preview/nnlm-en-dim128/1", output_shape = [128], input_shape = [], dtype = tf.string, name = 'input', trainable = False ) model = tf.keras.Sequential() model.add(hub_layer) model.add(tf.keras.layers.Dense(64, activation = 'relu')) model.add(tf.keras.layers.Dense(3, activation = 'softmax', name = 'output')) model.compile( loss = 'categorical_crossentropy', optimizer = 'Adam', metrics = ['accuracy'] ) model.summary() print("\n\nsave untrained_model.pickle\n\n") model.save(untrained_model.path)
Конвейер Kubeflow определяется в «pipeline_amazon.yaml» следующим образом:
@dsl.pipeline(name = "train_amazon_pipeline") def my_pipeline(epochs: int = 10, batch_size: int = 12, num_samples: int = 10000, url_train: str = "https://www.dropbox.com/s/tdsek2g4jwfoy8q/train.csv?dl=1", url_test: str = "https://www.dropbox.com/s/tdsek2g4jwfoy8q/test.csv?dl=1"): download_train_data_task = load_dataset(url = url_train, num_samples = num_samples) nnlm_model = nnlm_model_download() train_model_task = train( epochs = epochs, batch_size = batch_size, input_labels_artifacts = download_train_data_task.outputs["output_labels_artifacts"], input_text_artifacts = download_train_data_task.outputs["output_text_artifacts"], input_untrained_model = nnlm_model.outputs["untrained_model"] ) download_test_data_task = load_dataset(url = url_test, num_samples = num_samples) eval_model_task = eval_model( input_model = train_model_task.outputs["output_model"], input_labels_artifacts = download_test_data_task.outputs["output_labels_artifacts"], input_text_artifacts = download_test_data_task.outputs["output_text_artifacts"] ) kfp.compiler.Compiler(mode = kfp.dsl.PipelineExecutionMode.V2_COMPATIBLE).compile( pipeline_func = my_pipeline, package_path = 'pipeline_amazon.yaml' )
Создайте файл yaml конвейера «pipeline_amazon.yaml»:
python3 kfp_train_amazon.py
Этот короткий обучающий пример модели определяет простые компоненты и один конвейер в одном файле «kfp_train_amazon.py». Реальные крупномасштабные производственные проекты повторно используют как компоненты, так и фрагменты конвейера в нескольких конвейерах, а также включают модульные тесты как для компонентов, так и для сегментов конвейера.
Конвейеры Kubeflow можно легко развернуть в нескольких производственных средах с помощью — локальных, управляемых и локальных кластеров Kubeflow/Kubernetes, которые, в свою очередь, планируют и сохраняют выполнение конвейера:
Результаты
Kubeflow/Kubernetes — файл «pipeline_amazon.yaml», сгенерированный автоматически, определяет «рабочий процесс» контроллера Kubernetes и контейнеры компонентов:
Точность — «pipeline_amazon.yaml» подходит для данных обучения длиной в десять тысяч предложений с точностью обучения-валидации 0,95 и 0,75 соответственно. Обучение с полными данными устраняет переобучение и точность проверки 97%:
python3 train_amazon_refactured.py # run time approx. 20mins 5 epochs. Validation: 8883/8883 [=========] - 2020s 227ms/step - loss: 0.1355 - accuracy: 0.9723
MLOps и стресс-тест — мой 32-ядерный 130-гигабитный Fedora 36 может планировать десятки одновременно работающих конвейеров:
python3 kfp_stress.py
с ресурсами Docker, установленными на 20 ядер и 64 ГБ памяти. Незаметно, поскольку этот простой пример полностью загружает обучающие и тестовые данные в память, память является основным узким местом для конвейеров, работающих параллельно. Я использую кеш компонентов Kubeflow, который позволяет пропустить выполнение контейнера для идентичных компонентов и параметров:
Моему 2-ядерному 8-гигабитному mac Book mini удается выполнить всего несколько заданий, но конечная точка Kubeflow часто дает сбой. В состоянии «ожидания» локально установленный кластер Kubeflow/Kubernetes запускает 14 развертываний.
Будущая работа
Контейнеризация — рефакторинг кода в образ докера и создание четырех новых компонентов и конвейеров с использованием контейнеров.
Память — найдите решение для узкого места памяти
Выводы — создать обслуживающий сервис с помощью компонента докера eval-model.
GPU — добавьте обучение GPU Tensorflow и логические выводы, а также оцените ускорение. Планирование новых ресурсов GPU для локального кластера Kubeflow: https://jacobtomlinson.dev/posts/2022/quick-hack-adding-gpu-support-to-kind/
Метаданные — сохраняйте базу данных Kubeflow по умолчанию, используемую для хранения метаданных о заполненных контейнерах. Эти данные будут потеряны при сбое локального кластера Kubeflow и желательно хранить метаданные о выполненных задачах в отдельном постоянном хранилище.
Сетевые узкие места — сетевые компоненты с низким уровнем вычислений, загружающие данные, становятся узким местом в стрессовых развертываниях, таких как сотни одновременно работающих конвейеров, в то время как высокие вычислительные нагрузки эффективно обрабатываются кластером.
Advanced MLOps — создайте производственный уровень с другой платформой ML (MLFlow, AirFlow, MetaFlow и др.) и сравните с Kubeflow/Kubernetes.
Advanced MLOps — разверните новую главную и две подчиненные виртуальные машины, установите новый кластер Kubeflow, определите новый планировщик и запланируйте GPU на подчиненных узлах.
Advanced MLOps — установите облачную платформу на новые виртуальные машины (OpenStack или аналогичные) и настройте ресурсы, такие как выделение узлов GPU и автоматическое масштабирование.