Машинне навчання як послуга з TensorFlow

Уявіть собі: ви потрапили на борт AI Hype Train і вирішили розробити програму, яка проаналізує ефективність різних типів паличок. Щоб монетизувати цей приголомшливий додаток для штучного інтелекту та вразити ВК, нам потрібно буде відкрити його для світу. І краще, щоб це було масштабовано, оскільки всі захочуть ним користуватися.

Як вихідну точку ми будемо використовувати цей набір даних, який містить вимірювання ефективності прищипування їжі різних людей паличками різної довжини.

Архітектура

Оскільки ми є не тільки вченими даних, але й відповідальними інженерами програмного забезпечення, спочатку ми розробимо нашу архітектуру. По-перше, нам потрібно буде вирішити, яким чином ми отримаємо доступ до нашої розгорнутої моделі, щоб робити прогнози. Для TensorFlow наївним вибором буде використання TensorFlow Serving. Цей фреймворк дозволяє розгортати навчені моделі TensorFlow, підтримує моделювання версій та використовує gRPC під капотом.

Головне застереження щодо gRPC полягає в тому, що він не надто зручний для громадськості порівняно, наприклад, з послугами REST. Той, хто має мінімальний інструментарій, може зателефонувати у службу REST і швидко повернути результат. Але коли ви використовуєте gRPC, спочатку потрібно створити клієнтський код із прото-файлів за допомогою спеціальних утиліт, а потім написати клієнт улюбленою мовою програмування.

TensorFlow Serving спрощує багато речей у цьому конвеєрі, але все-таки це не найпростіший фреймворк для споживання API на стороні клієнта. Подумайте про службу TF, якщо вам потрібен блискавичний, надійний, строго набраний API, який буде використовуватися всередині вашої програми (наприклад, як серверна служба для веб- або мобільного додатка).

Нам також потрібно буде задовольнити нефункціональні вимоги до нашої системи. Якщо багато користувачів можуть знати їх рівень ефективності паличок, нам потрібна система, яка буде стійкою до несправностей та масштабованою. Крім того, команді інтерфейсу потрібно буде десь розгорнути свій веб-додаток chopstick'o'meter. І нам знадобляться ресурси для створення прототипів нових моделей машинного навчання, можливо, в лабораторії Юпітера з великою кількістю обчислювальної потужності. Однією з найкращих відповідей на ці питання є використання Kubernetes.

Kubernetes - це система з відкритим кодом для автоматизації розгортання, масштабування та управління контейнерними програмами.

Маючи Kubernetes на місці, отримавши знання та деякий час, ми можемо створити масштабоване власне хмарне рішення PaaS, яке надає інфраструктуру та програмне забезпечення для розробки науково-дослідного проекту повного циклу. Якщо ви не знайомі з Kubernetes, пропоную переглянути це:

Kubernetes працює на базі технології Docker, тому, якщо ви їй не знайомі, можливо, спочатку прочитайте офіційний посібник.

Загалом, це дуже багата тема, яка заслуговує на повне висвітлення кількох книг, тому тут ми зупинимось на одній частині: перенесенні моделей машинного навчання на виробництво.

Міркування

Так, цей набір даних невеликий. І так, застосування глибокого навчання може бути не найкращою ідеєю тут. Тільки майте на увазі, що ми тут, щоб вчитися, і цей набір даних, безумовно, цікавий. Частина моделювання цього посібника буде недостатньо якісною, оскільки основна увага приділяється процесу розгортання моделі.

Крім того, нам потрібно справити враження на наші ВК, тому глибоке навчання є обов’язковим! :)

Код

Усі файли коду та конфігурації, використані в цій публікації, доступні у супутньому сховищі GitHub.

Навчальний класифікатор глибокої палички

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

Як ви можете знати, ми можемо навчити наш класифікатор двома способами: за допомогою TensorFlow та за допомогою TensorFlow Estimator API. Estimator API - це спроба представити уніфікований інтерфейс для моделей глибокого навчання таким чином, як scikit-learn робить це для набору класичних моделей ML. Для цього завдання ми можемо використовувати tf.estimator.LinearClassifierшвидку реалізацію логістичної регресії та експорт моделі після завершення навчання.

Інший спосіб, який ми можемо зробити, - це використовувати звичайний TensorFlow для підготовки та експорту класифікатора:

Налаштування обслуговування TensorFlow

Отже, у вас є дивовижна модель глибокого навчання з TensorFlow і ви прагнете її впровадити у виробництво? Тепер настав час взяти до рук сервіс TensorFlow.

TensorFlow Serving заснований на gRPC - швидкій віддаленій бібліотеці викликів процедур, яка використовує інший проект Google під капотом - Буфери протоколів.

Буфери протоколів - це структура серіалізації, яка дозволяє трансформувати об'єкти з пам'яті в ефективний двійковий формат, придатний для передачі по мережі.

Щоб підбити підсумок, gRPC - це фреймворк, який дозволяє віддалені виклики функцій через мережу. Він використовує буфери протоколів для серіалізації та десеріалізації даних.

Основними компонентами TensorFlow Serving є:

  • Обслуговуваний - це в основному версія вашої навченої моделі, експортованої у форматі, придатному для завантаження TF Serving
  • Завантажувач - сервісний компонент TF, який, за збігом обставин, завантажує в пам'ять серверні дані
  • Менеджер - реалізує операції життєвого циклу, що обслуговуються. Він контролює народження (завантаження), довгожиття (обслуговування) та смерть (розвантаження)
  • Core - змушує всі компоненти працювати разом (офіційна документація трохи розмита щодо того, що таке ядро, але ви завжди можете подивитися на вихідний код, щоб зрозуміти, що він робить)

Ви можете прочитати більш глибокий огляд архітектури обслуговування TF в офіційній документації.

Щоб запустити та запустити послугу на базі TF Serving, вам потрібно:

  1. Експортуйте модель у формат, сумісний з TensorFlow Serving. Іншими словами, створіть сервіс.
  2. Встановіть або скомпілюйте TensorFlow Serving
  3. Запустіть TensorFlow Serving і завантажте останню версію експортованої моделі (можна вручну)

Налаштування сервісу TernsorFlow можна виконати кількома способами:

  • Будівництво з джерела. Для цього потрібно встановити Bazel і завершити тривалий процес компіляції
  • Використання заздалегідь побудованого двійкового пакета. Обслуговування TF доступне як пакет deb.

To automate this process and simplify subsequent installation to Kubernetes, we created a simple Dockerfile for you. Please clone the article’s repository and follow the instructions in the README.md file to build TensorFlow Serving Docker image:

➜ make build_image

This image has TensorFlow Serving and all dependencies preinstalled. By default, it loads models from the /models directory inside the docker container.

Running a prediction service

To run our service inside the freshly built and ready to use TF Serving image, be sure to first train and export the model (or if you’re using a companion repository, just run the make train_classifier command).

After the classifier is trained and exported, you can run the serving container by using the shortcut make run_server or by using the following command:

➜ docker run -p8500:8500 -d --rm -v /path/to/exported/model:/models tfserve_bin
  • -p maps ports from the container to the local machine
  • -d runs the container in daemon (background) mode
  • --rm removes the container after it has stopped
  • -v maps the local directory to a directory inside the running container. This way we pass our exported models to the TF Serving instance running inside the container

Calling model services from the client side

To call our services, we will use grpctensorflow-serving-api Python packages. Please notice that this package is currently only available for Python 2, so you should have a separate virtual environment for the TF Serving client.

To use this API with Python 3, you’ll either need to use an unofficial package from here then download and unzip the package manually, or build TensorFlow Serving from the source (see the documentation). Example clients for both Estimator API and plain TensorFlow are below:

Going into production with Kubernetes

If you have no Kubernetes cluster available, you may create one for local experiments using minikube, or you can easily deploy a real cluster using kubeadm.

We’ll go with the minikube option in this post. Once you have installed it (brew cask install minikube on Mac) we may start a local cluster and share its Docker environment with our machine:

➜ minikube start...➜ eval $(minikube docker-env)

After that, we’ll be able to build our image and put it inside the cluster using

➜ make build_image

A more mature option would be to use the internal docker registry and push the locally built image there, but we’ll leave this out of scope to be more concise.

After having our image built and available to the Minikube instance, we need to deploy our model server. To leverage Kubernetes’ load balancing and high-availability features, we will create a Deployment that will auto-scale our model server to three instances and will also keep them monitored and running. You can read more about Kubernetes deployments here.

All Kubernetes objects can be configured in various text formats and then passed to kubectl apply -f file_name command to (meh) apply our configuration to the cluster. Here is our chopstick server deployment config:

Let’s apply this deployment using the kubectl apply -f chopstick_deployment.yml command. After a while, you’ll see all components running:

➜ kubectl get allNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGEdeploy/chopstick-classifier 3 3 3 3 1d
NAME DESIRED CURRENT READY AGErs/chopstick-classifier-745cbdf8cd 3 3 3 1d
NAME AGEdeploy/chopstick-classifier 1d
NAME AGErs/chopstick-classifier-745cbdf8cd 1d
NAME READY STATUS RESTARTS AGEpo/chopstick-classifier-745cbdf8cd-5gx2g 1/1 Running 0 1dpo/chopstick-classifier-745cbdf8cd-dxq7g 1/1 Running 0 1dpo/chopstick-classifier-745cbdf8cd-pktzr 1/1 Running 0 1d

Notice that based on the Deployment config, Kubernetes created for us:

  • Deployment
  • Replica Set
  • Three pods running our chopstick-classifier image

Now we want to call our new shiny service. To make this happen, first we need to expose it to the outside world. In Kubernetes, this can be done by defining Services. Here is the Service definition for our model:

As always, we can install it using kubectl apply -f chopstick_service.yml. Kubernetes will assign an external port to our LoadBalancer, and we can see it by running

➜ kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEchopstick-classifier LoadBalancer 10.104.213.253  8500:32372/TCP 1dkubernetes ClusterIP 10.96.0.1  443/TCP 1d

As you can see, our chopstick-classifier is available via port 32372 in my case. It may be different in your machine, so don’t forget to check it out. A convenient way to get the IP and port for any Service when using Minikube is running the following command:

➜ minikube service chopstick-classifier --url//192.168.99.100:32372

Inference

Finally, we are able to call our service!

python tf_api/client.py 192.168.99.100:32372 1010.0Sending requestoutputs { key: "classes_prob" value { dtype: DT_FLOAT tensor_shape { dim { size: 1 } dim { size: 3 } } float_val: 3.98174306027e-11 float_val: 1.0 float_val: 1.83699980923e-18 }}

Before going to real production

As this post is meant mainly for educational purposes and has some simplifications for the sake of clarity, there are several important points to consider before going to production:

  • Use a service mesh like linkerd.io. Accessing services from randomly generated node ports is not recommended in production. As a plus, linkerd will add much more value to your production infrastructure: monitoring, service discovery, high speed load balancing, and more
  • Use Python 3 everywhere, as there is really no reason to use Python 2 now
  • Apply Deep Learning wisely. Even though it is a very general, spectacular, and widely applicable framework, deep learning is not the only tool at the disposal of a data scientist. It’s also not a silver bullet that solves any problem. Machine learning has much more to offer. If you have relational/table data, small datasets, strict restrictions on computation resources, or training time or model interpretability, consider using other algorithms and approaches.
  • Reach out to us if you need any help in solving machine learning challenges: [email protected]