[PYTHON] Essayez d'exécuter Distributed TensorFlow sur Google Cloud Platform

Au fait, j'ai appris le mécanisme de Distributed Tensorflow avec la dernière fois et précédent. Exécutons-le enfin sur Google Cloud Platform (GCP). Si vous créez beaucoup d'instances de vCPU en insérant la trame libre de \ $ 300, vous pouvez voir les échelles de puissance de feu élevée, même pour les pauvres. C'était ma motivation.

Lorsque je l'ai cassé pour la première fois, j'ai découvert que le compte gratuit de GCP était limité à 8 processeurs virtuels par région, donc ce n'était pas si élevé. Cette fois, un vCPU a été attribué à chaque interface et un au serveur maître, il sera donc parallélisé avec six vCPU. Pourtant, bien sûr, c'est plus rapide.

Créer une image Docker

Je veux l'exécuter sur Container Engine de GCP, alors créez d'abord une image Docker.

Créez une image de conteneur tf \ _server pour le worker qui contient uniquement le serveur Tensorflow qui a été créé l'autre jour, et une image de conteneur tf \ _if pour l'interface.

Tout d'abord, tf \ _server vient de copier le binaire de grpc \ _tensorflow \ _server dans / bin / de l'image ubuntu ordinaire. Je l'ai répertorié dans docker.io/ashipong/tf_server.

Ajoutons un peu plus de tf \ _if. Copiez la version Tensorflow distribuée de whl construite avec bazel et

$ sudo apt-get install python python-pip python-dev
$ pip install tensorflow-0.7.1-py2-none-any.whl

J'ai pu installer le TensorFlow compatible distribué lui-même. Ce serait pratique si vous pouviez y accéder avec jupyter notebook, alors installez jupyter également. Configurez également le serveur notebook. Décrivez ~ / .jupyter / jupyter \ _notebook \ _config.py selon ici. Le mot de passe est "distribué_tensorflow". Comme l'IP n'est pas restreinte et qu'elle est dangereuse, ceux qui publient cette image doivent prendre toutes les précautions possibles telles que restreindre l'IP de la source d'accès et réécrire le mot de passe dès que possible.

こちらも同様にdockerhubに上げました。docker.io/ashipong/tf_ifです。

Pratique du TensorFlow distribué sur Docker sous OSX

Vérifions si cela fonctionne de la même manière avec l'image Docker. Premièrement, il n'y a qu'un seul serveur grpc.

$ docker run -d -p 2222:2222 ashipong/tf_server /bin/grpc_tensorflow_server  --cluster_spec='master|localhost:2222' --job_name=master --task_index=0 &

Configurer un serveur avec et depuis le client,

import tensorflow as tf
c = tf.constant("Hello, distributed TensorFlow on docker!")
sess = tf.Session("grpc://192.168.99.100:2222")
sess.run(c)

Accès comme. 192.168.99.100 est l'adresse IP de docker-machine. Cela a fonctionné correctement.

Ensuite, que se passe-t-il s'il y a deux conteneurs sur le serveur? Configurez un conteneur de serveur comme indiqué ci-dessous.

$ docker run -d -p 2222:2222 --name tf_master ashipong/tf_server /bin/grpc_tensorflow_server --cluster_spec='master|192.168.99.100:2222,slave|192.168.99.100:2223' --job_name=master --task_index=0 &
$ docker run -d -p 2223:2222 --name tf_slave ashipong/tf_server /bin/grpc_tensorflow_server --cluster_spec='master|192.168.99.100:2222,slave|192.168.99.100:2223' --job_name=slave --task_index=0 &

Les deux conteneurs ouvrent un serveur sur le port 2222. Du côté de l'hôte, nous nous connecterons au 2222223. Étant donné que les conteneurs peuvent être connectés à l'aide de la [fonction de réseau virtuel] de docker (http://qiita.com/Arturias/items/75828479c1f9eb8d43fa), l'adresse IP et le port vus du côté hôte sont décrits dans cluster_spec. Eh bien, je ne peux pas bien l'écrire, mais est-ce que c'est comme ça?

docker.png

De cette manière, vous pouvez augmenter le nombre de conteneurs les uns après les autres dans un environnement où docker peut être utilisé, mais comme vous pouvez le voir à partir de la procédure ci-dessus, cluster_spec peut accéder à l'adresse IP et au port de tous les conteneurs qui composent le cluster TensorFlow à partir de chaque conteneur. Doit être écrit sous forme. Si vous souhaitez exécuter chaque conteneur sur une machine différente, vous devez configurer un réseau afin que les conteneurs exécutés sur différentes machines puissent communiquer entre eux.

Distributed MNIST

Comme prévu, dans le modèle qui se rapproche fonctionnellement de $ y = exp (x) $ utilisé jusqu'à précédent, la charge augmente considérablement même si le nombre de lots est augmenté. Puisqu'il n'y a rien de tel, je pense qu'il serait préférable d'avoir un modèle avec des données un peu plus volumineuses. C'est pourquoi j'ai essayé de paralléliser le standard MNIST. Ici est une version unique, [ici](https://github.com/ashitani/DistributedTensorFlowSample/blob/ master / gcp / mnist / mnist_distributed.py) est la version distribuée du code.

En gros, j'ai juste appliqué ce que j'ai fait dans La dernière fois à MNIST. J'ai beaucoup de collections, mais je pourrai peut-être écrire plus efficacement.

Vers GCP (résultats)

Maintenant, exécutons-le enfin avec GCP. Nous commencerons par les résultats. Comme mentionné au début, j'ai créé 8 clusters avec 1 vCPU et affecté respectivement if (interface) et 6 maîtres et workers. Le nom du travail et le nom du cluster (pod) sont identiques.

La composition est la suivante lorsqu'elle est écrite dans une image.

gcp.png

Du coup, ça ressemble à ça pour un single.

# python mnist_single.py
step 00000, training accuracy 0.123, loss 1762.99, time 1.253 [sec/step]
step 00010, training accuracy 0.218, loss 1308.50, time 1.293 [sec/step]
step 00020, training accuracy 0.382, loss 1191.41, time 1.223 [sec/step]
step 00030, training accuracy 0.568, loss 1037.45, time 1.235 [sec/step]
step 00040, training accuracy 0.672, loss 939.53, time 1.352 [sec/step]
step 00050, training accuracy 0.742, loss 853.92, time 1.303 [sec/step]
...

La version distribuée ressemble à ceci. Passez le nom de la machine sur laquelle le serveur maître s'exécute comme argument. Cette fois, il porte le même nom que master.

# python mnist_distributed.py master
step 00000, training accuracy 0.130, loss 1499.24, time 0.433 [sec/step]
step 00010, training accuracy 0.597, loss 839.25, time 0.405 [sec/step]
step 00020, training accuracy 0.828, loss 437.39, time 0.478 [sec/step]
step 00030, training accuracy 0.893, loss 220.44, time 0.438 [sec/step]
step 00040, training accuracy 0.902, loss 219.77, time 0.383 [sec/step]
step 00050, training accuracy 0.942, loss 131.92, time 0.370 [sec/step]
...

C'est environ 3x la vitesse. Comme il y a 6 personnes, cela ne peut pas être 6 fois plus rapide, mais si c'est 3 fois plus rapide, c'est un gros problème car c'est aussi différent que de peindre l'avion en rouge et d'ajouter des coins. Un filet plus profond montrera sa vraie valeur. Il semble que la plaque de dispersion soit meilleure pour le degré de convergence, mais cette fois je n'ai pas fait correspondre la graine du nombre aléatoire, alors passons simplement.

À propos, avec mon Macbook Pro, la version unique a pris environ 0,8 seconde. Vous pouvez le faire plus rapidement que Macbook Pro, au moins gratuitement. (Eh bien, la vitesse de GCP varie en fonction du degré de congestion)

Vers GCP (procédure)

Maintenant, notez les étapes GCP qui ont conduit à ce qui précède. Je suis un débutant dans le cloud qui a commencé Docker pour une raison quelconque, donc je fais peut-être des choses stupides, mais pardonnez-moi s'il vous plaît.

Commencez par créer un projet à partir du Web GCP. Après cela, c'est une opération du client.

Tout d'abord, mettons l'ID dans la variable d'environnement. Associez votre machine à votre projet.

$ export PROJECT_ZONE=YOUR_ZONE
$ export PROJECT_ID=YOUR_PROJECT
$ gcloud config set project ${PROJECT_ID}
$ gcloud config set compute/zone ${PROJECT_ZONE}

Ensuite, transférez l'image de conteneur que vous avez créée précédemment dans le registre des conteneurs.

$ docker tag ashipong/tf_server asia.gcr.io/${PROJECT_ID}/tf_server
$ gcloud docker push asia.gcr.io/${PROJECT_ID}/tf_server
$ docker tag ashipong/tf_if asia.gcr.io/PROJECT_ID/tf_if
$ gcloud docker push asia.gcr.io/${PROJECT_ID}/tf_if

Créez un cluster de conteneurs sur le Container Engine. Le nom est tf.

$ gcloud container clusters create tf --num-nodes 8 --machine-type n1-standard-1
$ gcloud container clusters get-credentials tf

Créez des pods avec 1 if, 1 master et 6 workers dans le cluster. Le pod est un fichier master.yml comme celui ci-dessous

master.yml


apiVersion: v1
kind: Pod
metadata:
  name: master
  labels:
    app: tfserver
spec:
  containers:
    - name: master
      command: ["/bin/grpc_tensorflow_server"]
      args: ["--cluster_spec=master|master:2222,worker0|worker0:2222,worker1|worker1:2222,worker2|worker2:2222,worker3|worker3:2222,worker4|worker4:2222,worker5|worker5:2222,","--job_name=master","--task_index=0"]
      image: asia.gcr.io/${PROJECT_ID}/tf_server
      ports:
        - containerPort: 2222
  nodeSelector:
    app: master

Faites quelque chose comme

$ kubectl create -f master.yml

Vous pouvez faire comme ça, mais il est difficile de se préparer pour tout le monde, j'ai donc créé Generation Script. En conséquence, le réglage de nodeSelector n'était pas nécessaire, mais j'ai pensé qu'il serait préférable d'associer le nœud et le pod pendant le débogage, j'ai donc étiqueté le côté du nœud et le nœud et le pod associés. Cette zone est également réalisée avec le script de génération.

Cette fois, j'ai fait un pod avec un autre nom, worker0, worker1, .... Ce serait cool si le worker pouvait être défini sur un pod et que le nombre de conteneurs pouvait être augmenté ou diminué tout en surveillant la charge, mais le serveur grpc_tensorflow_server actuel doit décrire tous les autres membres dans l'argument cluster_spec au démarrage. Si vous modifiez le nombre de conteneurs ultérieurement, vous devrez redémarrer tous les serveurs. Je pense qu'un mécanisme plus sophistiqué sera libéré du chef de famille ou quelque part dans ce domaine.

Quoi qu'il en soit, je vais étiqueter le nœud avec le script de génération suivant et faire le tour pour configurer le pod.

$ python ./create_tf_servers.py

Vérifiez si le pod a été généré.

$ kubectl get pods
NAME      READY     STATUS    RESTARTS   AGE
if        1/1       Running   0          1m
master    1/1       Running   0          1m
worker0   1/1       Running   0          1m
worker1   1/1       Running   0          1m
worker2   1/1       Running   0          1m
worker3   1/1       Running   0          1m
worker4   1/1       Running   0          1m
worker5   1/1       Running   0          1m

La dernière chose à laquelle j'étais accro était la résolution de noms entre chaque pod. Configurez-vous généralement DNS? Cette fois, j'ai abandonné et j'ai écrit dans les hôtes. C'est le plus cool.

Ci-dessous, vous pouvez voir les adresses IP attribuées aux pods.

$ kubectl get pods -o=yaml |grep podIP

De là, j'ai lancé vi directement et l'ai édité. C'est le plus cool.

$ kubectl exec -it master vi /etc/hosts

Maintenant que nous sommes enfin prêts, connectez-vous à if et exécutez le script.

$ kubectl exec -it if /bin/bash
# apt-get install git
# cd home
# git clone https://github.com/ashitani/DistributedTensorFlowSample
# cd DistributedTensorFlowSample/gcp/mnist
# python mnist_distributed.py master

bash semble expirer dans environ 5 minutes. Est-ce quelque chose comme exec / bin / bash? Dans if, jupyter notebook est lancé, donc je pense que vous devriez publier le service et entrer à partir de là, mais cette fois, ça passera.

Si vous êtes un utilisateur GCP, vous le ferez probablement plus intelligemment, mais j'ai réussi à le faire fonctionner, alors je vais arrêter de le faire. Avec 8 processeurs virtuels, c'est la limite de la motivation (rires)

finalement

C'est la fin de la trilogie post liée à Ichiou Distributed Tensoflow.

Cette fois, j'ai créé un cluster sur GCP et essayé d'exécuter la version parallèle de données de MNIST. Malheureusement, je n'ai pas pu ressentir autant la vitesse explosive avec le niveau gratuit, mais si j'avais l'argent (rires), je pense que je pourrais augmenter le nombre d'instances et m'amuser.

Si la vitesse est d'environ x10, je pense qu'un GPU est suffisant, mais si vous visez x100 ou une zone plus rapide, vous devrez utiliser le GPU et le cluster ensemble. J'ai hâte de voir l'instance GPU de GCP.

Pour le rendre encore plus rapide que cela, le matériel et l'avenir immédiat seraient FPGA. L'autre jour, il y avait une excellente déclaration de Google Veuillez rendre moins cher parce que vous pouvez réduire la fiabilité du stockage. Pour le dire de manière extrême, je pense que cela signifie prendre en charge le contrôle qualité de l'usine de stockage sur place. Je pense que l'une des raisons pour lesquelles les FPGA sont chers est le rendement en éléments, mais comme le réseau neuronal profond est souvent configuré pour résister à la déconnexion locale, il est appelé FPGA pour l'apprentissage en profondeur, ce qui est extrêmement bon marché au lieu de réduire le rendement. Ne va-t-il pas bientôt arriver sur le marché? Je l'attends sans autorisation.

Recommended Posts

Essayez d'exécuter Distributed TensorFlow sur Google Cloud Platform
Essayez d'exécuter tensorflow sur Docker + anaconda
Essayez Distributed Tensor Flow
Consultez les prévisions météo sur M5Stack + Google Cloud Platform
Essayez StyleGAN avec Google Colaboratory
Créer un environnement de développement Ubuntu python sur Google Cloud Platform
Essayez d'exécuter Jupyter Notebook sur Mac
Essayez les données en parallèle avec TensorFlow distribué
Essayez d'utiliser Bash sur Windows 10 2 (installation de TensorFlow)
Essayez d'exécuter le jugement d'image PlaidML sur Mac
Essayez d'exécuter le simulateur 3D de Kobuki sur ROS
Essayez d'exécuter Google Chrome avec Python et Selenium
J'ai essayé d'exécuter YOLO v3 avec Google Colab
[GoogleCloudPlatform] Utiliser l'API Google Cloud avec la bibliothèque cliente d'API
Essayez d'exécuter Pyston 0.1
Exécution de MINST dans TensorFlow 2.0 et visualisation dans TensorBoard (version 2019)
Comment se connecter à Cloud SQL PostgreSQL sur Google Cloud Platform à partir d'un environnement local avec Java