最強GPUを自由に触れる食べログの開発環境を紹介するよ

はじめまして、エンジニアとして ML やら DevOps をやっている @kamina_zzz です。
Advent Calendar 2日目の今日は食べログの最強な機械学習開発環境について紹介していきます。

よろしくお願いいたします!

## 経緯

機械学習における学習フェーズでは行列計算の占める割合が多い傾向にあります。
行列計算に強い GPU を使った機械学習が注目されて久しく、特に画像認識などにおいては「GPU を使うのが主流だよね!」といった雰囲気さえあります(_要出典_)。

一方、食べログはありがたいことに多くのユーザーさんに使って頂いており、2018/10/01 時点では[国内総合37位](https://www.similarweb.com/ja/top-websites/japan)、[Food and Drink カテゴリにおいては国内1位](https://www.similarweb.com/ja/top-websites/japan/category/food-and-drink)のトラフィックがあります。

このトラフィックをベースとしためちゃくちゃにデカいログなどのデータを日々データレイクに投げ込んでいまして、学習にはこのデータを使っていくわけです。
まともにやり合おうとすると計算量的にまずい予感がします。

というか、工夫してうまいこと圧縮したとしてもかかる時間は短いに越したことはありません。

さらにさらに、どうせなら **最強** で **使い倒せる環境** がほしいじゃないですか。ほしいですよね。

## 構築

最強で使い倒せる環境って人によってはいろんな回答があるかと思いますが、食べログでは以下のようになりました。

### オンプレミス

クラウドの利用が非常に盛んな今日このごろですが、クラウドで GPU インスタンスを見てみるとめちゃめちゃ高いです。

これはまずい。
お上も「こんなに高いんだとちょっと…プロトタイプくらいは Mac で作って?」となりかねないです。あぶない。

それではエンジニアの作業にも影響が出てしまいそうですし、「許可をとって…」とか「予算が…」とかしているうちにスピード感は落ちてしまいます。
食べログではオンプレミスのマシンを受け入れるための環境が **たまたま** ありましたので、オンプレミスでの構築を採用しています。

### NVIDIA Tesla V100

そもそも機械学習ライブラリの多くは NVIDIA のライブラリを使用することが多く(というか AMD のものを僕が知らない)、NVIDIA 製の商用 GPU で最強なのを選定したらコレになりました。

せっかくなので2枚入れておきます。

### Docker の利用

Web アプリの世界だけでなく ML の世界でももはやコンテナの利用は一般的となってきています。
依存ライブラリの解決や並列化など、様々なメリットがあるため食べログの ML 環境もコンテナベースの運用となっています。

複数ホスト上で多数の pod によるスケーラブルな学習を手軽にできるよう、Kubernetes 環境を構築することも決まっており、現在鋭意構築中です。

---

## 結果

いざ実際に動かしてみるとその凄さがわかります。

うちの子がどんなにすごいか少しだけ自慢させていただくために GPU を使って MNIST やってみます。


1\. GPU マシン上でコンテナ起動

```
$ nvidia-smi -L
GPU 0: Tesla V100-PCIE-16GB (UUID: GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
GPU 1: Tesla V100-PCIE-16GB (UUID: GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)

$ sudo nvidia-docker run -it tensorflow/tensorflow:latest-gpu-py3 bash
```

2\. MNIST 実行して時間測ってみます

```
$ time python3 mnist_cnn.py

Using TensorFlow backend.
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
Train on 60000 samples, validate on 10000 samples
Epoch 1/12

# ~ 中略 ~

2018-mm-dd 00:00:00.000000: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14873 MB memory) -> physical GPU (device: 0, name: Tesla V100-PCIE-16GB, pci bus id: 0000:08:00.0, compute capability: 7.0)
2018-mm-dd 00:00:00.000000: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:1 with 14873 MB memory) -> physical GPU (device: 1, name: Tesla V100-PCIE-16GB, pci bus id: 0000:84:00.0, compute capability: 7.0)
60000/60000 [==============================] - 8s 139us/step - loss: 0.2796 - acc: 0.9140 - val_loss: 0.0588 - val_acc: 0.9822
Epoch 2/12
60000/60000 [==============================] - 3s 47us/step - loss: 0.0906 - acc: 0.9732 - val_loss: 0.0428 - val_acc: 0.9853
Epoch 3/12
60000/60000 [==============================] - 3s 47us/step - loss: 0.0690 - acc: 0.9796 - val_loss: 0.0357 - val_acc: 0.9886
Epoch 4/12
60000/60000 [==============================] - 3s 47us/step - loss: 0.0559 - acc: 0.9834 - val_loss: 0.0325 - val_acc: 0.9885
Epoch 5/12
60000/60000 [==============================] - 3s 47us/step - loss: 0.0470 - acc: 0.9856 - val_loss: 0.0287 - val_acc: 0.9908
Epoch 6/12
60000/60000 [==============================] - 3s 47us/step - loss: 0.0418 - acc: 0.9874 - val_loss: 0.0287 - val_acc: 0.9908
Epoch 7/12
60000/60000 [==============================] - 3s 48us/step - loss: 0.0372 - acc: 0.9887 - val_loss: 0.0281 - val_acc: 0.9909
Epoch 8/12
60000/60000 [==============================] - 3s 47us/step - loss: 0.0342 - acc: 0.9895 - val_loss: 0.0287 - val_acc: 0.9904
Epoch 9/12
60000/60000 [==============================] - 3s 46us/step - loss: 0.0322 - acc: 0.9903 - val_loss: 0.0277 - val_acc: 0.9916
Epoch 10/12
60000/60000 [==============================] - 3s 46us/step - loss: 0.0296 - acc: 0.9909 - val_loss: 0.0248 - val_acc: 0.9926
Epoch 11/12
60000/60000 [==============================] - 3s 45us/step - loss: 0.0280 - acc: 0.9914 - val_loss: 0.0284 - val_acc: 0.9909
Epoch 12/12
60000/60000 [==============================] - 3s 45us/step - loss: 0.0266 - acc: 0.9919 - val_loss: 0.0368 - val_acc: 0.9884
Test loss: 0.03678337639837555
Test accuracy: 0.9884

real    0m43.708s
user    0m50.604s
sys     0m29.223s
```

いやこれ、めっちゃ早くないですか?
ちなみに手元の Mac だと **24分** とかかかりました。

以上、食べログの開発環境について紹介させていただきました。
明日は @weakboson による「ハァイ、ジョージィ！reverse proxy立ててくれないのかい？」です。

お楽しみに〜!