Strojno učenje kao usluga s TensorFlowom

Zamislite ovo: ušli ste u AI Hype Train i odlučili razviti aplikaciju koja će analizirati učinkovitost različitih vrsta štapića. Da bismo unovčili ovu nevjerojatnu AI aplikaciju i impresionirali VC-ove, morat ćemo je otvoriti svijetu. I bolje bi bilo da je skalabilan jer će ga svi htjeti koristiti.

Kao polaznu točku koristit ćemo ovaj skup podataka koji sadrži mjerenja učinkovitosti stezanja hrane različitih pojedinaca štapićima različitih duljina.

Arhitektura

Kako nismo samo znanstvenici podataka već i odgovorni softverski inženjeri, prvo ćemo izraditi našu arhitekturu. Prvo ćemo morati odlučiti o tome kako ćemo pristupiti našem ugrađenom modelu da bismo predviđali. Za TensorFlow naivan izbor bio bi korištenje TensorFlow posluživanja. Ovaj vam okvir omogućuje primenu obučenih modela TensorFlow, podržava verziranje modela i koristi gRPC ispod haube.

Glavno upozorenje u vezi s gRPC je da nije previše prikladan za javnost u usporedbi s, na primjer, uslugama REST. Svatko s minimalnim alatima može nazvati REST uslugu i brzo vratiti rezultat. Ali kada koristite gRPC, prvo morate generirati klijentski kôd iz proto datoteka pomoću posebnih uslužnih programa, a zatim napisati klijenta na svom omiljenom programskom jeziku.

TensorFlow Serving pojednostavljuje puno stvari u ovom cjevovodu, ali ipak, to nije najlakši okvir za konzumiranje API-ja na klijentskoj strani. Razmislite o posluživanju TF-a ako vam treba munjevit, pouzdan, strogo upisan API koji će se koristiti unutar vaše aplikacije (na primjer kao pozadinska usluga za web ili mobilnu aplikaciju).

Također ćemo morati zadovoljiti nefunkcionalne zahtjeve za naš sustav. Ako puno korisnika možda želi znati njihovu razinu učinkovitosti štapića, trebat će nam sustav koji će biti otporan na greške i skalabilan. Također, tim korisničkog sučelja trebat će negdje smjestiti i svoju web-aplikaciju chopstick'o'meter. A trebat će nam resursi za prototipiranje novih modela strojnog učenja, vjerojatno u Jupyter Labu, s puno računalne snage iza sebe. Jedan od najboljih odgovora na ta pitanja je korištenje Kubernetesa.

Kubernetes je sustav otvorenog koda za automatizaciju postavljanja, skaliranja i upravljanja kontejnerskim aplikacijama.

Uz Kubernetes na mjestu, s obzirom na znanje i neko vrijeme, možemo stvoriti prilagodljivo interno PaaS rješenje u oblaku koje daje infrastrukturu i softver za razvoj projekata cjelokupnog ciklusa znanosti. Ako vam Kubernetes nije poznat, predlažem da pogledate ovo:

Kubernetes radi na vrhu Docker tehnologije, pa ako vam nije poznata, možda bi bilo dobro prvo pročitati službeni vodič.

Sve u svemu, ovo je vrlo bogata tema koja zaslužuje nekoliko knjiga da je u potpunosti obrade, pa ćemo se ovdje usredotočiti na jedan dio: premještanje modela strojnog učenja u proizvodnju.

Razmatranja

Da, ovaj je skup podataka mali. I da, primjena dubokog učenja možda nije najbolja ideja ovdje. Samo imajte na umu da smo ovdje da učimo, a ovaj skup podataka sigurno je zabavan. Dio za modeliranje ovog vodiča nedostajat će u kvaliteti, jer je glavni fokus na procesu implementacije modela.

Također, moramo impresionirati naše VC-ove, tako da je duboko učenje neophodno! :)

Kodirati

Sve datoteke koda i konfiguracije korištene u ovom postu dostupne su u popratnom GitHub spremištu.

Klasifikator dubokog štapića za trening

Prvo, moramo odabrati okvir za strojno učenje koji ćemo koristiti. Budući da je ovaj članak namijenjen demonstraciji mogućnosti posluživanja TensorFlowa, mi ćemo odabrati TensorFlow.

Kao što možda znate, dva su načina na koji možemo osposobiti naš klasifikator: pomoću TensorFlow i TensorFlow Estimator API. Estimator API je pokušaj predstavljanja jedinstvenog sučelja za modele dubokog učenja na način na koji scikit-learn to čini za skup klasičnih ML modela. Za ovaj zadatak možemo koristiti tf.estimator.LinearClassifierza brzu implementaciju logističke regresije i izvoz modela nakon završetka obuke.

Drugi način na koji to možemo jest koristiti obični TensorFlow za obuku i izvoz klasifikatora:

Postavljanje posluživanja TensorFlow

Dakle, imate strašan model dubokog učenja s TensorFlowom i željni ste ga staviti u proizvodnju? Sada je vrijeme da se uhvatimo za TensorFlow posluživanje.

TensorFlow Serving temelji se na gRPC - brzoj biblioteci poziva za udaljene postupke koja koristi drugi Googleov projekt ispod haube - Protocol Buffers.

Međuspremnici protokola okvir je za serializaciju koji vam omogućuje pretvaranje objekata iz memorije u učinkovit binarni format pogodan za prijenos mrežom.

Da rezimiramo, gRPC je okvir koji omogućuje udaljene pozive funkcija putem mreže. Koristi međuspremnike protokola za serializaciju i deserializaciju podataka.

Glavne komponente TensorFlow posluživanja su:

  • Posluživo - ovo je u osnovi verzija vašeg obučenog modela koji se izvozi u formatu prikladnom za učitavanje TF posluživanja
  • Utovarivač - TF Servisna komponenta koja slučajno učitava servisne predmete u memoriju
  • Upravitelj - provodi operacije životnog ciklusa posluživih. Kontrolira rođenje (utovar), dugo življenje (služenje) i smrt (istovar)
  • Jezgra - čini da sve komponente rade zajedno (službena dokumentacija pomalo je nejasna o tome što je zapravo jezgra, ali uvijek možete pogledati izvorni kod da biste saznali što radi)

Detaljniji pregled arhitekture posluživanja TF možete pročitati u službenoj dokumentaciji.

Da biste pokrenuli i pokrenuli uslugu temeljenu na TF posluživanju, morat ćete:

  1. Izvezite model u format kompatibilan s TensorFlow posluživanjem. Drugim riječima, stvorite Servable.
  2. Instalirajte ili kompajlirajte TensorFlow posluživanje
  3. Pokrenite TensorFlow Serving i učitajte najnoviju verziju izvezenog modela (posluživo)

Postavljanje posluživanja TernsorFlow može se izvršiti na nekoliko načina:

  • Zgrada iz izvora. To zahtijeva da instalirate Bazel i dovršite dugotrajan postupak kompilacije
  • Korištenje unaprijed izgrađenog binarnog paketa. TF posluživanje dostupno je kao deb paket.

Da bismo automatizirali ovaj postupak i pojednostavili naknadnu instalaciju na Kubernetes, stvorili smo jednostavnu Dockerfile za vas. Molimo klonirajte spremište članka i slijedite upute u datoteci README.md za izgradnju slike TensorFlow Serving Dockera:

➜ make build_image

Ova slika ima TensorFlow Serving i sve ovisnosti koje su unaprijed instalirane. Prema zadanim postavkama učitava modele iz /modelsdirektorija unutar spremnika dockera.

Pokretanje usluge predviđanja

Da biste pokrenuli našu uslugu u svježe izgrađenoj i spremnoj za upotrebu TF Serving slike, prvo obučite i izvezite model (ili ako koristite prateće spremište, samo pokrenite make train_classifiernaredbu).

Nakon što se klasifikator obuči i izveze, spremnik za posluživanje možete pokrenuti pomoću prečaca make run_serverili pomoću sljedeće naredbe:

➜ docker run -p8500:8500 -d --rm -v /path/to/exported/model:/models tfserve_bin
  • -p preslikava portove iz spremnika na lokalni stroj
  • -d pokreće spremnik u daemon (pozadinskom) načinu
  • --rm uklanja spremnik nakon što se zaustavio
  • -vpreslikava lokalni direktorij u direktorij unutar tekućeg spremnika. Na taj način prosljeđujemo naše izvezene modele instanci TF Serving koja se izvodi unutar spremnika

Pozivanje usluga modela s klijentske strane

Za pozivanje naših usluga koristit ćemo se grpctensorflow-serving-apiPython paketima. Napominjemo da je ovaj paket trenutno dostupan samo za Python 2, tako da biste trebali imati zasebno virtualno okruženje za klijenta TF posluživanja.

Da biste koristili ovaj API s Pythonom 3, morat ćete odatle upotrijebiti neslužbeni paket, a zatim ručno preuzeti i raspakirati paket ili izgraditi TensorFlow Serving iz izvora (pogledajte dokumentaciju). Primjeri klijenata za Estimator API i obični TensorFlow nalaze se u nastavku:

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]