Блокноты Kubeflow: эксперименты с машинным обучением стали проще — часть 2

Первоначально опубликовано на kubesimplify.com

Машинное обучение — очень итеративный процесс, в котором вам, возможно, придется провести массу экспериментов. В этой статье я познакомлю вас с блокнотами Kubeflow, способом запуска сред разработки внутри вашего кластера Kubernetes, а также с тем, как вы можете расширить стандартные возможности блокнотов Kubeflow для своих собственных вариантов использования и как это работает внутри.

Предыдущие статьи цикла

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

Ноутбуки Kubeflow

Блокноты Kubeflow позволяют запускать веб-среды разработки внутри вашего кластера Kubernetes, запуская их внутри модулей.

У такой настройки есть несколько преимуществ:

  • Вы можете создавать контейнеры Notebook и запускать их непосредственно в кластере, а не локально.
  • Вы можете использовать предварительно настроенные или пользовательские образы для создания среды, что позволит вам сосредоточиться на текущей задаче, а не на среде или проблемах установки.
  • Вы можете легко использовать возможности расширений с блокнотами Kubeflow и в этой статье, а в последующих статьях мы также рассмотрим обтекатель Kubeflow среди прочего.
  • Готовая поддержка JupyterLab, RStudio и VS Code, однако вы можете использовать любые другие IDE.
  • Наконец, возможности контроля доступа Kubeflow на основе ролей значительно упрощают простой и безопасный обмен ноутбуками.

Создайте сервер для ноутбуков

Прежде чем говорить больше о каких-либо конкретных компонентах блокнотов Kubeflow, давайте сначала взглянем на создание сервера блокнотов Kubeflow и запустим некоторый пример кода на вашем сервере блокнотов. Один сервер ноутбуков Kubeflow может содержать несколько ноутбуков, и вы, вероятно, хотели бы иметь несколько серверов ноутбуков для разных этапов жизненного цикла машинного обучения в соответствии с вашими потребностями.

Создать сервер Kubeflow Notebook с помощью пользовательского интерфейса довольно просто, и у вас есть возможность указать:

  • Имя записной книжки и рабочей области, к которой она принадлежит.
  • Docker-образ для вашего Notebook Server, это образ, который будет запускать наш контейнер, и вы можете понимать его как способ указать, что вы хотите, чтобы среда содержала. Это также настраивается в соответствии с вашими потребностями, и мы увидим больше об этом в специальном разделе этой статьи.
  • ЦП и ОЗУ, которые сервер ноутбука пытается запросить.
  • Укажите, нужны ли вам графические процессоры в модулях Notebook, Kubeflwo достигает этого с ограничениями, как показано в Документации Kubernetes.
  • Том рабочей области, который будет смонтирован как том PVC в вашей домашней папке.
  • Один или несколько томов данных должны быть смонтированы как тома PVC. Об этом мы тоже поговорим подробнее.
  • Конфигурации — это способ вставки общих данных (env vars, volumes) в блокноты. Kubeflow создал контроллер PodDefault на основе Kubernetes PodPreset (теперь устарел), который вы можете использовать для достижения этой цели. Вы можете создавать манифесты PodDefault, которые описывают дополнительные требования времени выполнения (например, том, VolumeMounts, переменные среды), которые будут внедрены в под во время создания.
  • Как вы могли догадаться, вы также можете указать привязку и конфигурацию taint для серверов Notebook.
  • Ноутбуки также позволяют включать общую память. Если вы используете что-то вроде torch.multiprocessing или torch.Tensor.share_memory_(), это сильно зависит от использования общей памяти.

Давайте теперь создадим сервер ноутбука, установив для изображения значение kubeflownotebookswg/jupyter-tensorflow-full:v1.6.0-rc.1, которое содержит TensorFlow 2.5.3 и некоторые другие часто используемые библиотеки. Позже мы увидим, как вы также можете настроить эти изображения. При нажатии «Запуск» создается новый CRD ноутбука с этими настройками, и вскоре вы должны увидеть приглашение, позволяющее подключиться к серверу ноутбуков.

Запустите пример блокнота

Давайте сначала попробуем настроить простой пример TensorFlow на сервере Notebook, вы, конечно, можете запустить любой блокнот, какой захотите.

git clone https://github.com/kubesimplify/kubeflow-series
cd kubeflow-series/2

Если вам интересно, почему на новой машине установлен Git, это потому, что образы Kubeflow по умолчанию содержат множество утилит, которые вам потребуются предварительно установленными. Теперь вы можете попробовать настроить tensorflow-example.ipynb, который содержит код обучения простой модели для TensorFlow 2 с использованием Keras.

На самом деле вы также можете использовать Jupyter Lab Extensions, и мы поговорим о таких расширениях, как KALE и Elyra, в следующих статьях.

Использование тензорной доски

В машинном обучении, чтобы что-то улучшить, часто нужно уметь это измерять. TensorBoard — это инструмент для обеспечения измерений и визуализации, необходимых в процессе машинного обучения. Он позволяет отслеживать метрики эксперимента, такие как потери и точность, визуализировать график модели, проецировать вложения в пространство меньшего размера и многое другое.

Давайте посмотрим на пример использования TensorBoard с Kubeflow.

Теперь вы должны запустить tensorboard.ipynb, это пример TensorFlow, но, как вы уже догадались, вы можете использовать TensorBoard и с любым другим фреймворком. Если вы заметили, что при выполнении этого примера мы создали каталог logs, в котором хранятся наши журналы TensorBoard.

Теперь вы можете создать экземпляр TensorBoard и использовать PVC, который у нас был для экземпляра Notebook, чтобы получить журналы TensorBoard, в моем случае это выглядит так:

И вуаля, у вас есть TensorBoard, который автоматически перезагружается из ваших журналов тренировок.

Что происходит при создании Notebook Server?

Мы уже создали сервер для ноутбуков, в качестве следующего шага было бы очень полезно узнать, как Kubeflow удается создать новый сервер для ноутбуков.

Всякий раз, когда вы создаете новый сервер Kubeflow Notebook, вы, по сути, создаете Kubernetes StatefulSet. И любой код, который вы запускаете на сервере Notebook, запускает дополнительные модули Kubernetes.

Проще говоря, StatefulSet — это контроллер, который помогает развертывать и масштабировать группы модулей Kubernetes. Контроллер StatefulSet также создает экземпляры PersistentVolumeClaims и управляет ими для каждого экземпляра пода, который мы рассмотрим подробнее в следующем разделе. StatefulSet обычно используется, когда вы хотите запустить несколько модулей одного типа параллельно, но каждый из модулей должен иметь определенное удостоверение.

Я подумал, что было бы интересно посмотреть журналы событий Kubernetes при создании блокнота, который теперь должен иметь гораздо больше смысла, поскольку вы уже знаете, как он работает внутри. Вот фрагмент событий, происходящих при создании блокнота:

statefulset/kubeflow-series-part2                       create Pod kubeflow-series-part2-0 in StatefulSet kubeflow-series-part2successful
notebook/kubeflow-series-part2                          Reissued from statefulset/kubeflow-series-part2: create Pod kubeflow-series-part2-0in StatefulSet kubeflow-series-part2 successful
persistentvolumeclaim/kubeflow-series-part2-volume      External provisioner is provisioning volume for claim "kubeflow-user-example-com/kubeflow-series-part2-volume"
persistentvolumeclaim/kubeflow-series-part2-volume      waiting for a volume to be created, either by external provisioner "csi.civo.com" or manually created by system administrator
persistentvolumeclaim/kubeflow-series-part2-volume      Successfully provisioned volume pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa
pod/kubeflow-series-part2-0                             Successfully assigned kubeflow-user-example-com/kubeflow-series-part2-0 to k3s-kubeflow-e183-917191-node-pool-7e46-n66x1
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Successfully assigned kubeflow-user-example-com/kubeflow-series-part2-0 to k3s-kubeflow-e183-917191-node-pool-7e46-n66x1
pod/kubeflow-series-part2-0                             AttachVolume.Attach succeeded for volume "pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa"
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: AttachVolume.Attach succeeded for volume "pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa"
pod/kubeflow-series-part2-0                             Container image "docker.io/istio/proxyv2:1.14.1" already present on machine
pod/kubeflow-series-part2-0                             Created container istio-init
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Created container istio-init
pod/kubeflow-series-part2-0                             Started container istio-init
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Started container istio-init
pod/kubeflow-series-part2-0                             Pulling image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1"
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Pulling image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1"
pod/kubeflow-series-part2-0                             Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
pod/kubeflow-series-part2-0                             Created container kubeflow-series-part2
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Created container kubeflow-series-part2
pod/kubeflow-series-part2-0                             Started container kubeflow-series-part2
pod/kubeflow-series-part2-0                             Container image "docker.io/istio/proxyv2:1.14.1" already present on machine
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Started container kubeflow-series-part2
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Container image "docker.io/istio/proxyv2:1.14.1" already present on machine
pod/kubeflow-series-part2-0                             Created container istio-proxy
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Created container istio-proxy
pod/kubeflow-series-part2-0                             Started container istio-proxy
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Started container istio-proxy

Действительно, при создании одного Notebook Server происходит довольно много вещей, но, учитывая то, что мы уже знаем, позвольте мне обратить ваше внимание, в частности, на следующие строки журнала:

statefulset/kubeflow-series-part2                       create Pod kubeflow-series-part2-0 in StatefulSet kubeflow-series-part2successful
...
persistentvolumeclaim/kubeflow-series-part2-volume      Successfully provisioned volume pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa
...
pod/kubeflow-series-part2-0                             AttachVolume.Attach succeeded for volume "pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa"
...
pod/kubeflow-series-part2-0                             Pulling image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1"
...
pod/kubeflow-series-part2-0                             Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
notebook/kubeflow-series-part2                          Reissued from pod/kubeflow-series-part2-0: Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
pod/kubeflow-series-part2-0                             Created container kubeflow-series-part2
pod/kubeflow-series-part2-0                             Started container kubeflow-series-part2
...

Этот отредактированный фрагмент журналов намного проще интерпретировать, и вот что он говорит нам о процессе создания сервера ноутбука:

  • Сначала Kubeflow создает StatefulSet, в котором создаются модули для нашего Notebook Server.
  • Для нашего Notebook Server kubeflow-series-part2-0 создается модуль, на котором выполняется наш код.
  • К этому модулю прикреплена специальная заявка на постоянный том (мы поговорим об этом подробнее позже), в которой находится наш домашний каталог при использовании сервера ноутбука.
  • Наш Notebook Server использует образ, который мы вставили, в этом примере kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1, и запускает контейнер в модуле.

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

Тома хранения для серверов ноутбуков

StatefulSet присваивает уникальные идентификаторы каждому модулю и позволяет легко хранить и отслеживать данные в постоянном томе данных, однако это совершенно отдельная сущность, чей жизненный цикл не зависит от модулей. Постоянный том — это ресурс кластера, подобный узлу внутри кластера. Это абстрагирует множество деталей о том, как предоставляется хранилище, из того, как оно используется, оно извлекает данные, необходимые для анализа, из основного хранилища и записывает изменения по мере необходимости.

Постоянный том данных подключается к определенному модулю с помощью утверждения постоянного тома, что позволяет пользователю использовать абстрактные ресурсы хранилища. В случае удаления сервера записной книжки данные по-прежнему сохраняются в постоянном томе данных, назначенном этому модулю, и если будет создан новый сервер записной книжки, он сможет получить доступ к тем же данным из того же постоянного тома данных.

Это (постоянные заявки на объем) похоже на Pod. Поды потребляют ресурсы узлов, а PVC — ресурсы PV. Поды могут запрашивать определенные уровни ресурсов (ЦП и памяти). Утверждения могут запрашивать определенный размер и режимы доступа (например, они могут быть смонтированы ReadWriteOnce, ReadOnlyMany или ReadWriteMany).

kubernetes.io

Чтобы настроить общий том хранилища, нам сначала нужно создать StorageClass Kubernetes, в идеале вы хотите, чтобы ваш класс хранилища обеспечивал динамическое выделение ресурсов. Вот простой пример создания тома Portworx, адаптированный из документации Kubernetes:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: portworx-io-priority-high
provisioner: kubernetes.io/portworx-volume
parameters:
  repl: "1"
  snap_interval:   "70"
  priority_io:  "high"

После того, как StorageClass (многие облака часто также предоставляют классы хранения по умолчанию, которые вы можете использовать точно так же) создан, мы можем настроить утверждения Persistent Volume Claims при создании сервера ноутбуков, используя параметр «Добавить новый том», вот пример на как вы могли бы сделать это с пользовательским интерфейсом:

Или вы также можете определить их с помощью спецификации YAML:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: shared-claim
  namespace: kubeflow-user-example-com
  annotations:
    volume.beta.kubernetes.io/storage-class: portworx-io-priority-high
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 8Gi

Kubeflow также позволяет легко управлять томами с помощью пользовательского интерфейса Kubeflow:

Как я показал ранее, помимо разделяемых томов хранения, сервер ноутбуков также должен иметь выделенный том.

Настройте свой сервер ноутбуков

В предыдущем разделе мы говорили о создании серверов ноутбуков и о том, как вы можете использовать готовые образы для своего сервера ноутбуков. Однако вы, возможно, заметили, что вы не ограничены готовыми изображениями, вы также можете указать свое собственное изображение, которое хотите использовать. Давайте посмотрим, как вы можете создавать образы для блокнотов Kubeflow.

Блокноты Kubeflow изначально поддерживают три типа блокнотов: JupyterLab, RStudio и Visual Studio Code, однако вы можете использовать любую другую веб-среду IDE в своем пользовательском образе. Вы можете найти список готовых образов ноутбуков здесь, а также базовые серверы ноутбуков, которые можно расширить здесь.

Документация Kubeflow содержит исчерпывающий список того, что необходимо для работы пользовательских образов с блокнотами Kubeflow. Чтобы блокноты Kubeflow могли работать с образом контейнера, образ должен:

  • открыть HTTP-интерфейс на порту 8888:
  • kubeflow устанавливает переменную среды NB_PREFIX во время выполнения с URL-адресом, который, как мы ожидаем, контейнер будет прослушивать.
  • kubeflow использует IFrame, поэтому убедитесь, что ваше приложение устанавливает Access-Control-Allow-Origin: * в заголовках ответа HTTP.
  • запустите от имени пользователя jovyan:
  • домашний каталог jovyan должен быть /home/jovyan
  • UID jovyan должен быть 1000
  • начать успешно с пустым PVC, установленным в /home/jovyan:
  • kubeflow монтирует PVC по адресу /home/jovyan, чтобы сохранить состояние при перезапуске пода

Вот пример создания образа поверх базового образа Jupyter, но с двумя дополнительными пакетами: tensorflow и fast-transformer:

FROM public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter:v1.5.0
RUN python3 -m pip install \
tensorflow==2.5.3 \
fast-transformer==0.2.0

Затем вы можете создать этот образ и отправить его с помощью любого инструмента, здесь мы будем использовать Docker:

TAG=0.1.0
docker build \
-t jupyter-tensorflow-example:${TAG} \
--f jupyter-tensorflow-example.Dockerfile . 
docker push ...

Рекомендуется строить поверх любого из базовых образов, однако вы не ограничены этим. Давайте посмотрим, как вы можете создать изображение, не используя ни одно из базовых изображений. Вот еще один пример, который позволяет получить те же 2 пакета, но не использует базовые изображения:

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
python3 \
python3-pip
RUN python3 -m pip --no-cache-dir install --upgrade \
"pip<20.3" \
setuptools
RUN python3 -m pip install --no-cache-dir \
jupyter \
tensorflow==2.5.3 \
fast-transformer==0.2.0
RUN apt-get install -y --no-install-recommends \
git \
libgl1-mesa-glx
EXPOSE 8888
ENV NB_PREFIX /
CMD ["bash","-c", "jupyter notebook --notebook-dir=/home/jovyan --ip=0.0.0.0 --no-browser --allow-root --port=8888 --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.allow_origin='*' --NotebookApp.base_url=${NB_PREFIX}"]

Таким же образом, как показано ранее, вы можете создать этот образ и отправить его с помощью любого инструмента.

После этого вы можете легко использовать этот образ при создании нового сервера Notebook, как показано на этом изображении.

Как Kubeflow поддерживает совместную работу?

В контексте блокнотов Kubeflow Kubeflow также поддерживает управление доступом на основе ролей для детального доступа к блокнотам. Notebook Server является частью пространства имен Kubeflow. Таким образом, несмотря на то, что в Kubernetes нет укоренившейся мультиарендности, Kubeflow Notebooks предлагает многопользовательскую изоляцию с пространствами имен и управлением доступом на основе ролей, которые он поддерживает прямо из коробки.

Поскольку Kubeflow Notebook Server основан на образе контейнера, он поставляется с библиотеками, фреймворками и инструментами, необходимыми для экземпляра Kubeflow Notebooks. Вы можете легко создать несколько разных серверов ноутбуков в соответствии с вашими потребностями, например: для обучения у вас может быть образ графического процессора TensorFlow при использовании образа на основе ЦП с различными библиотеками для анализа набора данных.

Вот отличная диаграмма, взятая с kubeflow.org, которая показывает мультиарендность в Kubeflow:

Учетная запись службы ноутбуков

Когда вы создаете новую записную книжку, Kubeflow по умолчанию назначает этому блоку Notebook default-editor Kubernetes ServiceAccount. Чтобы лучше понять, что это значит для вас как пользователя, вы можете запустить:

kubectl describe clusterrole kubeflow-edit

поскольку роль default-editor связана с kubeflow-edit ClusterRole.

Если вы видите выходные данные этой команды, мы видим, что при выполнении кода в модуле Notebook у вас есть привилегированная учетная запись default-editor Kubernetes ServiceAccount, привязанная к нему, и вы также можете отправлять ресурсы Kubernetes в блокноте. Это позволяет вам иметь отличную интеграцию с остальной архитектурой Kubeflow.

Заключение

Спасибо, что были со мной до конца. Я надеюсь, что вы усвоили кое-что о блокнотах Kubeflow и о том, как они работают, и вам понравилось это читать. Если вы узнали что-то новое или вам понравилось читать эту статью, поделитесь ею, чтобы другие могли ее увидеть. А пока, увидимся в следующем посте!

Мы продолжим то, о чем говорим в этой статье, в следующей статье этой серии, где мы углубимся в пайплайны Kubeflow, а пока прощайте!

Вы также можете найти меня в Твиттере @rishit_dagli, где я пишу о машинном обучении и открытом исходном коде.