WonderPlanet Tech Blog

アドバンストテクノロジー部やCTO室のメンバーを中心に最新の技術情報を発信しています。

nvidia-dockerをdocker-composeから使う

こんにちは。アドバンストテクノロジー部のR&Dチーム所属岩原です。
好きなKerasのLayerはDropoutです。

今回は、docker上でNVIDIA製GPUを使ったディープラーニング環境を構築してくれるnvidia-dockerの紹介と、
nvidia-dockerDocker-compose で使用する方法を導入から紹介したいと思います。

nvidia-dockerとは

Docker上でCUDAやcuDNNを使えるようにしたNVIDIA製のDockerプラグインです。
NVIDIA/nvidia-docker: Build and run Docker containers leveraging NVIDIA GPUs

Tensorflow-gpuがDocker上で動かせるようになるため、環境を選ばず(といってもNVIDIA製GPUは必要ですが)どこでもTensorflowやKerasをぶん回すことができるようになります。

ただし、nvidia-dockerを実行する場合、通常は以下のようなコマンドで実行します。

nvidia-docker run --rm nvidia/cuda nvidia-smi

この場合、docker-composeではnvidia-dockerが使えない事になります。

eywalker/nvidia-docker-compose: Simple wrapper for docker-compose to use GPU enabled docker under nvidia-dockerのようなdocker-composeを拡張したモジュールもありますが、
今回はそのような物をインストールせず、手軽に対応する方法をご紹介したいと思います。

まずは導入から始めましょう。

環境

  • OS:Ubuntu 16_04 LTS
  • GPU:GTX 1080 Ti 11GB
    • GPUは最近のNVIDIA製GPUであれば問題はないかと思います。
      GPUのアーキテクチャが Kepler であれば最新のCUDA9にも対応しています。

CUDA(& Driver)のインストール

nvidia-dockerにCUDAは本来必要ないのですが、ドライバー単体のインストールは面倒なので、CUDAもついでにインストールしてしまいます。
ドライバー単体はNVIDIAドライバダウンロードからダウンロード出来ます。
今回はCUDAのインストール手順をご紹介します。

手順

  1. CUDA Toolkit Download | NVIDIA DeveloperよりLinux -> x86_64 -> Ubuntu -> 16.04 -> deb(network) を選びます。
  2. Downloadのリンクアドレスをコピーします。
    • http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_9.0.176-1_amd64.deb のようなURLになっているはずです。バージョンによってURLは変わります。
  3. wget 2.でコピーしたURLでダウンロードします。
  4. 以下、Installation Instructions に沿ってコマンドを実行していきます。このあたりはCUDAのバージョンによって変わってくるので、画面の指示に従いましょう。以下は2017/11/2時点での最新の場合のコマンドになります。なお、最後に再起動するコマンドを追加しています。
sudo dpkg -i cuda-repo-ubuntu1604_9.0.176-1_amd64.deb
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
sudo apt-get update
sudo apt-get install cuda
sudo reboot

エラーが出た場合

sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub

上記実行時、

gpgkeys: protocol `https' not supported

というメッセージが出る場合があります。
この場合、

sudo apt-get install gnupg-curl

を実行した上で、再度コマンド実行すればOKです。

動作確認

nvidia-smiコマンドがエラーにならなければ正常にインストールされたことになります。

Dockerのインストール

古いDockerの削除(Docker CEになる前にdockerをインストールした人のみ)

sudo apt-get remove docker docker-engine docker.io で古いDockerを削除します。

手順

  1. 必要なパッケージのインストール
    sudo apt-get install apt-transport-https ca-certificates curl software-properties-common で必要なパッケージのインストールを行います。

  2. GPGキーの取得
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - でDocker公式のGPGキーを取得&追加します。

  3. リポジトリの追加
    sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" でリポジトリの追加を行います。 今回はstable ですが testedgeと言ったバージョンも指定できます。

  4. パッケージの更新
    sudo apt-get update でパッケージの更新を再度行います。

  5. Docker CEのインストール
    sudo apt-get install docker-ce でdockerのインストールを行います。

  6. 動作確認
    sudo docker run hello-worldHello from Docker! が表示されれば問題なくインストールされています。

nvidia-dockerのインストール

wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.1/nvidia-docker_1.0.1-1_amd64.deb
sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb

コレだけです。

nvidia-dockerを動かしてみる

nvidia-docker run --rm nvidia/cuda nvidia-smi

を実行し、GPUドライバの情報が出力されれば、インストールは成功です。

Docker-composeのインストール

手順

以下のコマンドを実行します。

sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose version 1.16.1, build 1719ceb

のような表示がされればOKです。

Docker-composeで動かす方法

さて、本題の docker-compose コマンドでnvidia-dockerを動かす方法です。 先にdocker-compose.ymlを示します。

version: "3"
services:
    tensorflow_keras:
        build:
            dockerfile: Dockerfile
        volumes:
            - nvidia_driver_384.90:/usr/local/nvidia:ro
        devices:
            - /dev/nvidiactl
            - /dev/nvidia-uvm
            - /dev/nvidia0
volumes:
    nvidia_driver_384.90:
        external: true

volumes でドライバを、devicesでGPUなどを指定してやる形になります。

nvidia_driver_384.90 の部分はインストールされているドライバのバージョンによって変わります。
nvidia-smiコマンドを実行して確認しましょう。

nvidia-smi
Mon Nov  6 07:14:16 2017
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.90                 Driver Version: 384.90                    |
|-------------------------------+----------------------+----------------------+

nvidia-docker を実行した際、必要なvolumeが作られてなければ自動作成されますが、 そうでない場合、以下のコマンドを実行し、自分でvolumeを作成してやる必要があります。

docker volume create --name=nvidia_driver_384.90 -d nvidia-docker

nvidia_driver_384.90384.90 はドライバーのバージョンによって変わりますので、適宜変えるようにしてください。

docker volume ls コマンドでDRIVERnvidia-docker になっているものが存在していればOKです。

docker volume ls | grep nvidia-docker
nvidia-docker       nvidia_driver_384.90

実際に動かしてみる

それでは、実際にnvidia-docker上で動かしてみましょう。
Kerasのサンプルの1つである、mnist + CNNを動かすDockerイメージを作ります。
keras/mnist_cnn.py at master · fchollet/keras

まず、ディレクトリ構造を以下の通りとします。

.
├── docker-compose.yml
└── tensorflow_keras
    ├── Dockerfile
    ├── entrypoint.sh
    ├── mnist_cnn.py
    └── requirements.txt

上から順に記載していきます。

docker-compose.yml

ほぼ先ほど紹介した内容に沿います。Dockerfileのディレクトリだけ違うので、それだけ追加しています。

version: "3"
services:
    tensorflow_keras:
        build:
            context: ./tensorflow_keras
            dockerfile: Dockerfile
        volumes:
            - nvidia_driver_384.90:/usr/local/nvidia:ro
        devices:
            - /dev/nvidiactl
            - /dev/nvidia-uvm
            - /dev/nvidia0
volumes:
    nvidia_driver_384.90:
        external: true

tensorflow_keras/Dockerfile

Tensorflowを使用するため、CUDA8 + CuDNN6の組み合わせのdockerイメージをベースに使用します。
OSはホストと同じUbuntu16.04を使用します。

FROM nvidia/cuda:8.0-cudnn6-runtime-ubuntu16.04

RUN apt-get update && \
    apt-get -y install wget build-essential gcc zlib1g-dev openssl libssl-dev libbz2-dev libreadline-dev libsqlite3-dev libmecab-dev mecab mecab-ipadic-utf8

# setup Python3.6
WORKDIR /tmp
RUN wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tgz \
        && tar zxf Python-3.6.1.tgz \
        && cd Python-3.6.1 \
        && ./configure \
        && make altinstall
ENV PYTHONIOENCODING "utf-8"

# pip install
COPY requirements.txt /tmp
RUN pip3.6 install -r /tmp/requirements.txt
RUN python3.6 --version

# setup my script
RUN mkdir /var/tensorflow_keras
COPY mnist_cnn.py /var/tensorflow_keras
WORKDIR /var/tensorflow_keras

# setup endpoint
COPY entrypoint.sh ./
RUN chmod +x ./entrypoint.sh
ENTRYPOINT ./entrypoint.sh

tensorflow_keras/entrypoint.sh

実行の確認さえできればいいので、Pythonスクリプトを実行するだけです。
無限待ちしたい場合は最後の tail -f /dev/null のコメントアウトを外します。

#! /bin/bash
python3.6 mnist_cnn.py
# tail -f /dev/null

tensorflow_keras/mnist_cnn.py

Kerasを使用してmnistの学習を行う簡単なサンプルです。
keras/mnist_cnn.py at master · fchollet/kerasからそのまま持ってきましょう。

requirements.txt

必要なPythonライブラリ群を記したものです。
現在の弊社環境のものを記載します。不要なものも混じってますが、参考までに。
基本的に、kerasとtensorflow-gpuのみ pip install すれば良いはずです。

bleach==1.5.0
h5py==2.7.1
html5lib==0.9999999
Keras==2.0.8
Markdown==2.6.9
numpy==1.13.1
pandas==0.20.3
protobuf==3.4.0
python-dateutil==2.6.1
pytz==2017.2
PyYAML==3.12
scikit-learn==0.19.0
scipy==0.19.1
six==1.10.0
tensorflow-gpu==1.3.0
tensorflow-tensorboard==0.1.6
Werkzeug==0.12.2
mecab-python3==0.7

実行結果

まずはイメージのビルドをします。

docker-compose build

次に実行します。

docker-compose up

すると、大量の出力とともに、結果が以下のように出力されるはずです。

〜〜〜〜 省略 〜〜〜〜
tensorflow_keras_1  | Epoch 10/12
60000/60000 [==============================] - 3s - loss: 0.0383 - acc: 0.9886 - val_loss: 0.0311 - val_acc: 0.9900
tensorflow_keras_1  | Epoch 11/12
60000/60000 [==============================] - 3s - loss: 0.0380 - acc: 0.9887 - val_loss: 0.0292 - val_acc: 0.9901
tensorflow_keras_1  | Epoch 12/12
60000/60000 [==============================] - 3s - loss: 0.0347 - acc: 0.9897 - val_loss: 0.0291 - val_acc: 0.9903
tensorflow_keras_1  | Test loss: 0.0291294318363
tensorflow_keras_1  | Test accuracy: 0.9903
tensorflow_keras_1  | Using TensorFlow backend.
tensorflow_keras_1 exited with code 0

ちなみに、GPUが使われているかどうかを判断するには、以下の出力があるかどうかでわかります。

tensorflow_keras_1  | 2017-11-02 06:12:18.275339: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:01:00.0)

docker-compose.ymlの記述が間違っていたりすると、

tensorflow_keras_1  | 2017-11-02 06:16:04.237736: E tensorflow/stream_executor/cuda/cuda_driver.cc:406] failed call to cuInit: CUDA_ERROR_NO_DEVICE

のような出力がされたり、CPUが使われるようになるので、以下のように学習時間がとても長くなったりします。

tensorflow_keras_1  | Epoch 1/12
60000/60000 [==============================] - 74s - loss: 0.3219 - acc: 0.9015 - val_loss: 0.0803 - val_acc: 0.9744

上記の例では、1epochで74sec掛かってることになります。およそ25倍時間がかかってます。

複数のGPUを持つマシンで、GPUを指定したい

以下のような構成の場合(例:AWSのp2.8xlarge)

ls -la /dev | grep nvidia
crw-rw-rw-  1 root root    195,   0 Nov  6 05:51 nvidia0
crw-rw-rw-  1 root root    195,   1 Nov  6 05:51 nvidia1
crw-rw-rw-  1 root root    195,   2 Nov  6 05:51 nvidia2
crw-rw-rw-  1 root root    195,   3 Nov  6 05:51 nvidia3
crw-rw-rw-  1 root root    195,   4 Nov  6 05:51 nvidia4
crw-rw-rw-  1 root root    195,   5 Nov  6 05:51 nvidia5
crw-rw-rw-  1 root root    195,   6 Nov  6 05:51 nvidia6
crw-rw-rw-  1 root root    195,   7 Nov  6 05:51 nvidia7
crw-rw-rw-  1 root root    195, 255 Nov  6 05:51 nvidiactl
crw-rw-rw-  1 root root    247,   0 Nov  6 05:51 nvidia-uvm
crw-rw-rw-  1 root root    247,   1 Nov  6 05:52 nvidia-uvm-tools

GPUが複数存在する事になります。 この場合、nvidia-dockerで使用するGPUを指定することが可能です。

docker-compose.ymlのdevicesを使用したいGPUにしてやることで可能となります。

version: "3"
services:
    tensorflow_keras:
        build:
            context: ./tensorflow_keras
            dockerfile: Dockerfile
        volumes:
            - nvidia_driver_384.90:/usr/local/nvidia:ro
        devices:
            - /dev/nvidiactl
            - /dev/nvidia-uvm
            - /dev/nvidia1  # ココ!
volumes:
    nvidia_driver_384.90:
        external: true

また、複数指定してやることも可能です。

version: "3"
services:
    tensorflow_keras:
        build:
            context: ./tensorflow_keras
            dockerfile: Dockerfile
        volumes:
            - nvidia_driver_384.90:/usr/local/nvidia:ro
        devices:
            - /dev/nvidiactl
            - /dev/nvidia-uvm
            - /dev/nvidia2  # ココ!
            - /dev/nvidia1  # ココ!
volumes:
    nvidia_driver_384.90:
        external: true

tensorflowでちゃんと複数認識します

tensorflow_keras_1  | 2017-11-06 07:29:00.244487: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:18.0)
tensorflow_keras_1  | 2017-11-06 07:29:00.244501: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:1) -> (device: 1, name: Tesla K80, pci bus id: 0000:00:19.0)

使用するGPUを割り振ることで、複数Dockerでも効率よく学習を行うことが出来ます。

まとめ

ホストマシンの環境に左右されてしまうところはありますが、環境さえ合わせてしまえば複数マシンで同じイメージが使用できるので、
ディープラーニング環境のポータビリティがよくなります。 また、バージョン違いのTensorflowも1つのマシンで共有できるので、1台のマシンで複数バージョンのCUDAを使用したい場合などに重宝します。

参考

iOS11 Core ML用モデルをAzureでサクッとつくる方法

こんにちはアドバンストテクノロジー部の@y-matsushitaです。
ついにiPhoneXが発売されましたね!ユーザは新しい体験にワクワクし開発者は未知のUIにドキドキしていることでしょう。
さて、今回はそんなiOSで使えるCore ML用の機械学習モデルをMicorsoft Azureで簡単につくる方法についてご紹介したいと思います。

Core MLについて

過去のブログでも取り上げていますが、iOS11から新たに追加されたアプリ上で機械学習モデルが読み込める機能です。
詳しくは先日のテックブログにまとめておりますので、「まだ読んでないよ」という方は是非そちらもご確認ください!

tech.wonderpla.net

問題点

Core ML用の機械学習モデルを自前で作るのは簡単ではありません。
(学習モデルの生成 & coremltoolsでの変換が必要)
多くの開発者は機械学習を始めようとしても必要な専門知識の量に苦労していることでしょう。

→そんな中Microsoft AzureでCore ML書き出しができるというので実際に試してみました。
 なんとコードを一切書く事なく短時間でCore MLモデルを作成することができます。


Microsoft Azure Custom Vision Service

利用にはアカウント登録が必要です。(要クレジットカード&電話番号)
お持ちでない方は以下のリンクからAzureのアカウントを取得しましょう。
azure.microsoft.com

アカウントが取得できたら、管理パネルにログインしてください。
f:id:y-matsushita:20171031190453j:plain:w600

Projectの作成

CustomVisionの管理パネルを開いたら、「New Project」から新規プロジェクトを作成します。
f:id:y-matsushita:20171031192101j:plain:w600

プロジェクトの情報を入力

f:id:y-matsushita:20171031192140j:plain:w600
Name : プロジェクト名
Description : 説明(省略可)
Domains : Core ML用に作る場合はGeneral(compact)のみ

機械学習用の画像をアップロード

サンプルとして犬と猫の画像を各30枚ほど用意しました。
30枚という枚数は非常に少ないのですが、公式によると30枚程度でも精度はでるとのことです。
f:id:y-matsushita:20171031192315j:plain:w600

これを以下の画面からアップロードします。
f:id:y-matsushita:20171031192349j:plain:w600

アップロード投稿はまとめて行うことができます。
f:id:y-matsushita:20171031192400j:plain:w600

画像にタグ付け

画像にこの画像が何なのか識別するためのタグを付けます。
今回は犬の画像をアップロードするので「dog」とタグをつけておきます。
f:id:y-matsushita:20171031192422j:plain:w750

アップロードが完了すると以下のような見た目になります。
f:id:y-matsushita:20171031192439j:plain:w750

犬の画像のアップロードが完了したら、
猫の画像も犬と同様にアップロードして「cat」とタグを付けておきます。

学習

画面右上の「Train」から学習を開始します。
f:id:y-matsushita:20171031192500j:plain:w750

しばらく待つと学習が完了します。
f:id:y-matsushita:20171031192517j:plain:w750

Core ML用のモデルのエクスポート

PERFORMANCE画面の「Export」から書き出しを行います。
もしここにExportのボタンが存在しない場合、プロジェクト作成時に設定したDomainsが「General(compact)」以外になっている恐れがあるので確認してください。
f:id:y-matsushita:20171031192535j:plain:w750

学習させたモデルがダウンロードできます。
f:id:y-matsushita:20171031192557j:plain:w300

「Export」をクリックすると「Download」ボタンが出てきます。
f:id:y-matsushita:20171031192613p:plain:w750

Core ML用の機械学習モデルを生成するだけでしたら、以上で作業完了です。
ダウンロードしたモデルをXcodeに持っていけばCore MLを活用した画像認識を試すことができます。
Core MLのモデルをアプリに組み込む方法については過去記事内の「学習モデルの取り込み」以降をご参考ください。
Core MLを利用した機械学習とVisionでの画像認識 - WonderPlanet Tech Blog

Core MLのアプリ上での動作結果

実際にアプリに組み込んだ結果は以下の通りです。
f:id:y-matsushita:20171101161524p:plain
iOSアプリに組み込んでも問題なく犬と猫の識別が出来ているようです。
(学習に用いた画像と背景やポーズが違いすぎると画像認識が上手くいかないことがあるようです)
また、Core ML書き出し以外にもAPIから呼び出すことが可能なので、
共通のモデルとして新たに別途作る必要なくWEBサービスなどに組み込む事も可能です。


学習させたモデルのテスト

もし作成したモデルのテストがしたい場合は、Core MLに書き出してXcodeに持っていかなくても
画面右上の「Quick Test」からブラウザ上で動作をチェックすることができます。
f:id:y-matsushita:20171031192637j:plain:w750

テストに使う画像をアップロード

学習に使用していない画像をアップロードします。
f:id:y-matsushita:20171031192655j:plain:w750

テスト結果

f:id:y-matsushita:20171031192713j:plain:w600
100%、catと出ました。少し出来過ぎな感じもしますが、期待通りの結果です。
このようにブラウザ上で画像をアップロードしてテストすることができます。

再学習

もしテストに使用した画像が理想の結果にならなかった場合は、
テストに使用した画像を利用してモデルを再学習させることができます。
f:id:y-matsushita:20171031192735j:plain:w750

新たに学習させたい画像をクリックしたら正解となる正しいタグを選択してセーブしてください。
f:id:y-matsushita:20171031192748j:plain:w750

画像のタグ付けが終わったら忘れず「Train」を実行して、再度モデルを生成しましょう。


最後に

AzureのCustom Vision Serviceは非常に少ない画像枚数でも、Core MLモデルを作り始めることができます。
理由はCustom Vision Service が使用する方法にあるそうで、小さな差異の影響を受けづらいからだそうです。

ただし逆に言えば微妙な差異を検出したいとき (品質保証の小さな割れやへこみなどの検出) にはCustom Vision Service はあまり適さないようです。 また判定の対象となるものが画像内のどこにあるかは今のところ識別しないようです。そのため対象が画像の角のほうに寄っていたり、対象が小さかったりすると識別が上手くいかないこともあるようです。ここらへんは更なる発展に期待ですね。

とはいえコードを一切書くことなく短時間でこの精度のCore MLモデルが作成できたのは、かなり凄いです!
試すのに時間はかからないので一度チャレンジしてみてはいかがでしょうか。

iOSアプリのiPhone X対応についていろいろ調べてみた

いよいよiPhone Xの発売日が迫ってきてウキウキしているアドバンストテクノロジー部の近藤です。

先日のWWDC 2017でiPhone Xが発表されました。
破壊的アップデートがなされることが発表されて、世界中のアプリエンジニアの皆さんは今から胃の痛い思いをしているかと思います。
iPhone Xにアプリを対応する上で主に画面の変更による注意点を、発売前にわかっている情報を元にまとめていきます。

iPhone X はこうなる

iPhone Xはパッと見てもわかるようにディスプレイの形がかなり変わっています。
f:id:HidehikoKondo:20171025190929p:plainf:id:HidehikoKondo:20171025190950p:plain

センサーハウジング(ディスプレイ上部の出っ張り)

Face ID用のセンサーやフロントカメラなどが収まっているエリアです。この部分が画面の内側までせり出しています。
その両側が従来のステータスバーとなり時計やバッテリー残量などが表示されます。

f:id:HidehikoKondo:20171025182958p:plain

ホームボタンの代わりにホームインジケータ

ホームボタンは廃止となり、その代わりにホームインジケータと呼ばれるUIが搭載されます。
画面の一番下に表示されている白い棒線の様なものがホームインジケータのUIです。
このエリアでスワイプすることで、ホームに戻る・アプリの切り替えの操作ができます。

f:id:HidehikoKondo:20171025183016p:plain

角が丸い

画面の角が丸くなります。
詳しくは後述しますが、この部分にはUIは配置できません。

アスペクト比が変わった

アスペクト比が約18:9となり縦長になります。

ガイドラインやWWDCでのKeynote

AppleからiPhone X に関するドキュメントやWWDCのkeynoteが公開されています。

iPhone X 対応でポイントとなる部分

アスペクト比の違い

写真などをフルスクリーンで表示するときは、アスペクト比が変わるため、端末の種類により画像が見切れることを考慮しなければなりません。 f:id:HidehikoKondo:20171020164459p:plain f:id:HidehikoKondo:20171020164659p:plain

レイアウトについて

  • センサーハウジングや角の丸い部分で必要な情報が隠れてはいけません。
  • センサーハウジングの左右の背景を黒くして、センサーハウジングがないように見せかけてはいけません。
  • UIKitを使ったアプリでは、Auto Layoutを利用していれば比較的簡単にiPhone Xに最適化できる(という記述がガイドラインにある)ので、Autoresizingはそろそろ卒業しましょう。

ステータスバー

  • ステータスバーの情報は消す必要が無い限りは非表示にはしない。
  • ステータスバーの高さが従来より高くなっています。
  • 通話中は時計が緑になるため、従来のようにステータスバーの高さは変わることはありません。 f:id:HidehikoKondo:20171020180144p:plain

背景

背景は画面いっぱいにフルスクリーンになるように配置します。

Safe Area

f:id:HidehikoKondo:20171020164851p:plain

  • Safe Areaという概念が新たに追加されました。
  • Safe AreaとMarginsの内側にUIを配置します。
  • 画面の角とホームインジケータに重ねてUIを配置はできません。(そもそもSafe Areaの外だからNG)
  • 画面スワイプなどのジェスチャーは、「ホームに戻るインジケータの操作を優先する」ため、そのエリア上では無視されます。
  • iPhone8以前の機種ではSafe Areaは画面いっぱいになります。

Landscape(横向き)表示の注意点

  • 動画は余白が出ないように拡大します(動画のアスペクト比によって余白が出るのは仕方ないと思う) f:id:HidehikoKondo:20171023124332p:plain
  • Landscape Right と Landscape Left両方でSafe Area内にUIが収まっているか確認する。画面の角やセンサーハウジングの付近に配置してはいけません。 f:id:HidehikoKondo:20171023123848p:plain
  • 動画広告やインタースティシャル広告を利用している場合、上記の点が守られているか確認しておきましょう。(広告SDKの提供元が対応する部分ですが)

各エリアのサイズ

f:id:HidehikoKondo:20171025152654p:plain

Cocos2d-xの画面はiPhone X でこうなります

f:id:HidehikoKondo:20171020165514p:plain

  • 青い部分がCocos2d-xのゲームのシーンが表示されるエリアです。
  • Safe Area内に収まっていますが、アスペクト比の違いにより上下に黒い余白ができてしまいます。
  • ガイドラインでNGとされている背景が黒くてセンサーの部分が隠れてしまっています。
  • ゲームのUIが画面の両端に配置してあった場合、Marginsのエリアに重なってしまいます。

 ※Cocos2d-xのバージョンは3.16で確認しています。

iPhone X で実行したときのみの個別対応が必要かも?

いい感じに背景を黒い部分に配置する、もしくはシーンが表示されるエリアを画面いっぱいに広げてシーン内のスプライトをSafe Area内に収まるように調整するなど、個別で対応が必要になることが予想されます。

Appleの審査

実際に審査に出してみないとわかりませんが、発売日以降は審査時にiPhone Xへの対応を求められると予想されます。
Xcode9からiPhone Xのシミュレータ *1 が利用できますので、可能な限り予め対応させておいたほうが良いと思います。
ガイドラインを正しく理解してできるだけガイドラインに沿ったレイアウトや実装にしましょう。
結局のところAppleのレビュアーのさじ加減なのは言うまでもありませんが・・・。

まとめ

上記のように変更点がたくさんあり、アプリだけに限らずWebサイトにも影響が出そうなiPhone X。
発売は楽しみですがデベロッパーの皆さんにはまた新たな難題が降り掛かってきた感じですね。
対応させるのは大変そうですが、Appleはこういうふうに作ってねというガイドラインをきちんとまとめてデベロッパーに向けて公開してくれています。
それを正しく理解して対応すればリジェクトされるようなこともないのではないでしょうか?

*1:Xcode9.0.1のiOS11シミュレーターでOpenGL系のバグがあり、Cocos2d-x・Unityなどのゲームエンジン、地図を利用したアプリなどの動作が非常に遅いでので注意。11月1日にリリースされたXcode9.1で、OpenGL系のバグは改善しています。

Kerasでメモリに乗り切らないぐらいの大量データを学習するたった1つの方法

こんにちは。アドバンストテクノロジー部のR&Dチーム所属岩原です。
今回はKerasを使ってメモリに乗り切らないぐらいの大量データを学習させる方法について紹介したいと思います。
個人的にハマったポイントなので、同じように困ってる方々の力になれれば…と思ってます。
Kerasとは何ぞや、とか使い方云々はまた別途記事を書きたいと思います。

対象読者

  • Kerasを使ってある程度の学習は出来る人
  • Pythonがある程度読める人
  • Unix系OSでKerasを動かしている人

今回はモデルの構築などは省略しています。

確認環境

  • Python:3.6.1
  • Keras:2.0.8
  • tensorflow-gpu:1.3.0 (今回は特に関係ありません)

想定場面

それでは、具体的な場面を想定してみましょう。

  • クエストのログを使って学習したい。クリア or notのデータがcsvデータとして手元にある。
  • クレンジングや怪しいデータの削ぎ落としをしても、データサイズが100GB近くになってしまっている。
  • 使えるマシンのメモリは16GBしかない。
  • AWSやGCPのGPUインスタンスが使えない環境である。

メモリ16GBのマシンでは、とてもじゃないけど100GBのデータは乗りませんね。どうしましょう。

いきなり結論

モデルのfit_generatorメソッドと、keras.utils.data_utils.Sequenceを実装したクラスを使います。
それぞれの定義はSequentialモデル - Keras Documentationfit_generatorと、ユーティリティ - Keras Documentationを参照していただきたいです。

いきなりコード(抜粋)

keras.utils.data_utils.Sequenceを実装したクラス

from keras.utils import Sequence
from pathlib import Path
import pandas
import numpy as np
from keras.utils import np_utils

class CSVSequence(Sequence):
    def __init__(self, kind, length):
        # コンストラクタ
        self.kind = kind
        self.length = length
        self.data_file_path = str(Path(download_path) / self.kind / "splited" / "split_data_{0:05d}.csv")

    def __getitem__(self, idx):
        # データの取得実装
        data = pandas.read_csv(self.data_file_path.format(idx), encoding="utf-8")
        data = data.fillna(0)
        
        # 訓練データと教師データに分ける
        x_rows, y_rows = get_data(data)
        
        # ラベルデータのカテゴリカル変数化
        Y = np_utils.to_categorical(y_rows, nb_classes) 
        X = np.array(x_rows.values)
        
        return X, Y

    def __len__(self):
        # 全データの長さ
        return self.length

    def on_epoch_end(self):
        # epoch終了時の処理
        pass

fit_generatorの呼び出し

from pathlib import Path
import multiprocessing

# csvダウンロード先パス
download_path = "/data"

# 同時実行プロセス数
process_count = multiprocessing.cpu_count() - 1


base_dir = Path(download_path)

# 訓練データ
train_data_dir = base_dir / "log_quest" / "splited"
train_data_file_list = list(train_data_dir.glob('split_data_*.csv'))
train_data_file_list = train_data_file_list

#検証用データ
val_data_dir = base_dir / "log_quest_validate" / "splited" 
val_data_file_list = list(val_data_dir.glob('split_data_*.csv'))
val_data_file_list = val_data_file_list

history = model.fit_generator(CSVSequence("log_quest", len(train_data_file_list)),
                steps_per_epoch=len(train_data_file_list), epochs=1, max_queue_size=process_count * 10,
                validation_data=CSVSequence("log_quest_validate", len(val_data_file_list)), validation_steps=len(val_data_file_list),
                use_multiprocessing=True, workers=process_count)

解説

前提

このコードでは、csvファイルは訓練用データディレクトリlog_questと検証用データディレクトリlog_quest_validateに分かれて入っている状態です。
さらに、それを並列で処理しやすいように、1000レコードずつ分割してsplitedディレクトリに入っています。
構造としてはこんな感じです。

/data/
├── log_quest
│   └── splited
│       ├── split_data_**.csv
└── log_quest_validate
     └── splited
        ├── split_data_**.csv

またsplit_data_**.csv は、正確にはsplit_data_{0:05d}.csvという命名形式に沿ってファイルを分割しています。
そのため、ファイルリストをCSVSequenceに渡さず、並列で処理を行っても競合したりせずに処理が可能になっています。

fit_generatorについて

このfit_generatorメソッドは、Pythonのジェネレータが生成するデータを受け取って学習を行うメソッドです。
学習画像の無限生成(画像の前処理 - Keras Documentation)に使われているのをネットで目にしますが、
自前のジェネレータ関数などでも問題なかったりします。
したがって、ジェネレータ関数で動的にデータを読み込んで返すようにすれば、メモリに乗り切らないぐらいの大量データでもどうにか返すことが出来ます。
しかし、今回はジェネレータではなく、CSVSequenceというkeras.utils.data_utils.Sequenceクラスを実装した独自クラスを指定しています。

また、fit_generatorメソッドは引数workersに1より大きい数字を指定すると並列処理をしてくれるようになります。
その場合、引数use_multiprocessingがTrueならマルチプロセス、Falseならマルチスレッドで並列処理を行います。

keras.utils.data_utils.Sequence とは?

fit_generatorメソッドで並列処理をしやすいようにしてくれるユーティリティクラスです。
ジェネレータでも並列で処理が呼ばれるのですが、並列処理なので呼び出し順序が不定であり、気をつけないと同じデータを学習してしまったりします。
それを防ぐユーティリティクラスがkeras.utils.data_utils.Sequenceです。
keras.utils.data_utils.Sequence クラスには実装すべきメソッドが3つあります(コンストラクタ合わせると4つ)。
各処理の詳細を解説します。

  • def __init__(self, kind, length)
    コンストラクタです。
    今回の例では、引数としてkind:ファイルの種別(訓練、検証)、length:ファイルリストの長さを受け取ります。
    また、コンストラクタ内でファイルパスの雛形を作成してます。

  • def __getitem__(self, idx)
    学習データを返すメソッドです。
    idxは要求されたデータが何番目かを示すインデックス値が入ります。
    (訓練データ, 教師データ)のタプルか、(訓練データ, 教師データ, sample_weights)のタプルで値を返す必要があります。
    また、タプルのそれぞれの要素はnumpy配列である必要があり、同じ要素数で揃える必要があります。
    このnumpy配列のサイズがバッチサイズとなります。
    今回の例では、コンストラクタで生成したファイルパスの雛形を元にファイルパスを作成し、
    それに該当するcsvデータをpandasで読み込み、訓練データと教師データに分割して返しています。

  • def __len__(self)
    学習データ全体の長さを返すメソッドです。
    __getitem__メソッドのidxの最大値は、ここで返した長さ - 1が設定されます。
    今回の例では、コンストラクタで渡されたファイルリストの長さをそのまま返しています。

  • def on_epoch_end(self)
    epoch終了時に呼び出されるメソッドです。
    epoch終了ごとに何か処理をしたい場合はここに記述します。
    今回の例では何もしていません。

マルチプロセス並列処理時の注意!

コンストラクタはメインプロセスで実行されますが、他のメソッドは子プロセスで実行されます。
従って、コンストラクタで設定するインスタンス変数は読み取り専用(各インスタンスメソッド内でインスタンス変数を書き換えても反映されない)で、かつpickleでシリアライズ可能である必要があります。
また、あまりにも大きすぎるデータだと、子プロセスに渡す際のオーバーヘッドが大きすぎて、時間がかかりすぎることがあります。

その他注意点など

  • fit_generatorメソッドの引数max_queue_sizeはデータ生成処理を最大いくつキューイングしておくか、という設定になります。
    メモリと相談しながらサイズを引き上げると良いでしょう。
  • fit_generatorメソッドの引数steps_per_epochはfit関数と同じく1epochでの学習回数を表します。
    基本的にSequenceの__len__と同じ値を指定すると良いでしょう。
  • マルチプロセスによる並列処理は、Windowsでは動作しません
    test_muliprocessing failed on windows · Issue #6582 · fchollet/kerasなどたくさんissueも上がってますが、対応される気配はありません…。UbuntuなどのLinux系OSを使いましょう。

Zoom Rooms を楽しく・便利に使うノウハウ大公開!

こんにちは、CTO村田です。前回に引き続き Zoom についてです。
今回は、Zoom Rooms をもっと楽しく、便利に使う方法を公開したいと思います。

前回の Zoom に関する記事をご覧になられていない方は、ご一緒にどうぞ!

tech.wonderpla.net

その前に... Zoom Rooms 設定画面の基本的なこと

Zoom Rooms に関する設定は、「ルーム管理」メニューより行います。
その中でも主に使うのは「Zoom Rooms」です。「カレンダー統合」は一度設定すれば、あまり触る事は無いと思います。

f:id:tomo-murata:20171016213853p:plain

そして Zoom Rooms の設定は、全体に反映する設定と、ルームごとの設定があります。

■ 全体に反映する設定

アカウント名の隣にある「アカウント設定」リンクから設定します。

f:id:tomo-murata:20171016114315p:plain

■ ルームごとの設定

「ルーム」タブ内のルーム一覧より、設定したいルームの「編集」ボタンから設定します。

f:id:tomo-murata:20171016114557p:plain

■ 表示言語の変更

設定画面も複数言語に対応し、今では日本語での表示が可能です。
とは言っても、ちょっと日本語がおかし箇所もあり、んんん??? となることも稀に...
そういう時は、 English にして確認した方が良いと思います。難しい英語もないので、個人的には English の方がオススメです。

言語切り換えは、画面右下にいつもあります。

f:id:tomo-murata:20171016214011p:plain

 
それでは、楽しく・便利になる方法を紹介していきます!!
 

ディスプレイの背景画像を変えたい

■ 目的
  • デフォルトの背景画像から別の画像に変えたい。
  • Zoom Rooms のディスプレイを見るだけで、どこの部屋なのか分かりたい。
■ 方法

ワンダープラネットでは、どの会議室なのかディスプレイを見ただけで分かるように背景画像を設定しております。

f:id:tomo-murata:20171016211907j:plain

ルーム編集の「ルームの設定」に「Zoom Roomsの背景画像」という項目があります。

f:id:tomo-murata:20171016112527p:plain

どのような画像を受け付けるかは、要件のところに記載されております。

また「ルームの設定」を見ていると、「ルームアバター」の設定もあります。

f:id:tomo-murata:20171016121522p:plain

こちらもぜひ併せて設定しましょう!
例えば Zoom Client 内の Zoom Rooms にアバターが表示されたりと、随所でルーム名と併せてアバターが表示されるようになります。

f:id:tomo-murata:20171016122021p:plain

ルームの Meeting ID を分かりやすい ID に固定にしたい

■ 目的
  • Meeting ID がコロコロ変わると、ホストルームに入る際にどの Meeting ID で入れば良いか分からない。
  • ランダムな数列の ID は覚えづらい。
■ 方法

ワンダープラネットでは、ある命名規則に則って、各ルームに Meeting ID を設定しております。
ちなみにMeeting ID は、10桁*1の数値 例)123-456-7890 です。 Meeting ID から 例)https://zoom.us/j/1234567890 というURLが発行され、このURLにアクセスするだけでミーティングに入ることもできます。

ただ、命名規則に則って Meeting ID を設定しているとは言え、なかなか覚えるのは厳しいです。
ワンダープラネットでは、Slack コマンドで呼び出せるようにしております。

f:id:tomo-murata:20171016145938p:plain

それでは、Meeting IDの設定と、必ずルームに割り当てた Meeting ID を使う方法です。

ルーム編集の「ルームの設定」に「ルームミーティングID」という項目があります。
こちらに希望の Meeting ID を入力します。

f:id:tomo-murata:20171016150558p:plain

「インスタントミーティングにパーソナルミーティングIDを使用する」にチェックを入れておくと、設定したルームミーティングIDでオンライン会議を開始します。

もっと楽に画面共有をしたい!

■ 目的
  • 画面共有するのに、Zoom Client を立ち上げるのすら面倒です。
  • HDMIケーブルを挿さずに、会議室のディスプレイに映したい。
■ 方法

Zoom Rooms の AirPlay *2機能を活用します。

前回、Zoom Rooms 用の機材として Mac mini を使っていると書きましたが、その理由がコレです!
Zoom Rooms は macOS と組み合わせることで、なんと AirPlay が使えるようになります*3。もうメチャクチャ便利です!!

AirPlay 機能を使うには、Zoom Rooms 用の機材として macOS 搭載の PC を用意するだけです。

では、AirPlayの使い方を見ていきましょう。

その1.macOS からの AirPlay

AirPlayのアイコンをクリックすると、Zoom Rooms のルームがずらっと並びます。今いる会議室を選択します。

f:id:tomo-murata:20171016153810p:plain

そうすると、Zoom Roomsのディスプレイに4桁の数値が現れます。

f:id:tomo-murata:20171016213134j:plain

PCにもパスワードを入力するダイアログが表示されますので入力します。

f:id:tomo-murata:20171016212935p:plain

たったこれだけです!

Zoom Rooms を使ったオンライン会議中であれば、相手にも共有されます。
Zoom Rooms でオンライン会議をしていない時でも AirPlay 可能です。ということは、HDMIなどのケーブルが無くても会議室のディスプレイに表示ができる!ということですね。

macOSの場合は、AirPlay 先を拡張ディスプレイとして扱えます。
PowerPoint や Keynote で作成したプレゼン資料を、ノートを見ながら説明することができます。Zoom Client で画面共有した時は違うところですね。

その2.iOS からの AirPlay

iOS のコントロールセンターから「画面ミラーリング」を選択します。

f:id:tomo-murata:20171016161308p:plain

AirPlay の一覧に Zoom Rooms のルームが並びますので、会議室を選択します。

f:id:tomo-murata:20171016160634p:plain

あとは macOS 同様、パスワードを入力ダイアログが表示されますので、ディスプレイに表示されたパスワードを入力します。

サウンドもちゃんと出力され、ゲームではよく見られる激しいエフェクトも遅延無く出力されます。
Zoom Client を経由するよりも軽いのでオススメです。

その3.上記以外からの AirPlay

Windows や Android から AirPlay をする方法を探してみましたが...
Windows の AirMyPC を使う方法しか、今のところ見つかっていないです。

他の AirPlay を実現するツールでは、接続はできるのですが真っ黒な四角が表示されるだけでした。画面共有はできず...

Zoom Rooms の異常を早く検知したい!

■ 目的
  • コントローラーとして使うタブレットがネットワークから切断されたり、バッテリーが無くなったりしている。
  • Zoom Rooms に接続されているスピーカーを外すのは良いけど、元に戻さず外されたままになっている。
  • このような状況になった時、早急に対応できるようにアラートをキャッチしたい。

運用していると Zoom Rooms が使えなくなるような状態が発生してきます...

■ 方法

アラートの設定ができますが、通知先に設定できるのは メールのみ です。
しかし、Slack には Slack でメールを受信する 機能があります。

これらを組み合わせることで、あまりメールを見ない方でも 簡単に Slack で通知を受け取ることができます。

それでは設定していきましょう。

1.ワークスペースにメールアプリを連携させる

Slack の App ディレクトリにアクセスして、 メール アプリを検索します。 email で検索すると最初の方に表示されます。

f:id:tomo-murata:20171016182616p:plain

「Add Configuration」より、通知するチャンネルを選択してメールアプリを追加します。

f:id:tomo-murata:20171016213343p:plain

そうすると、通知用のメールアドレスが発行されます。

f:id:tomo-murata:20171016183143p:plain

2.Zoom Rooms のアラートを有効にし、通知先を設定する

今回は、Zoom Rooms の設定でも「アカウント設定」から行います。
アカウント設定へ遷移すると、「アラートの設定」タブがあります。

f:id:tomo-murata:20171016183452p:plain

あとは、自分が把握したいアラート状況を設定し、最後に通知先メールアドレスとして、Slackで発行したメールアドレスを設定します。

f:id:tomo-murata:20171016183755p:plain

設定した異常状態になると、このように Slack に通知が飛んできます。

f:id:tomo-murata:20171016183943p:plain

これで、わざわざメールを開かなくても、Slackで状況を把握できますね!

■ 注意事項

Slack のメールアプリ追加は、有料プランでしか使えません。
無料プランで同様のことを行いたい場合は、転送用のメールアドレスを発行し、通知したい人数分登録しましょう。

次の会議が迫っていることを通知したい!

■ 目的
  • 会議室を使っている人が時間通りに会議を終わってくれない。
  • コントローラーにスケジュールが表示したい。
■ 方法

カレンダー統合機能を使います。

Zoom Rooms は、今のところ

  • Googleカレンダー
  • Office 365
  • Exchange

と連携できます。

ワンダープラネットでは G Suite を使っているため、今回は Googleカレンダーを使って説明します。

1.G Suite 側で連携専用のアカウントを発行する

連携専用のアカウントを発行します。社員の誰かのアカウントで連携してしまうと、見えてはマズイものが連携されますので止めましょう ^^;

アカウントを作成したら、そのアカウントからカレンダーのリソースを参照できるようにする必要があります。

2.連携専用アカウントでリソースを参照する

連携専用アカウントで G Suite にログインし、Googleカレンダーを開きます。

カレンダー設定 から「カレンダー」タブを開きます。 他のカレンダーのところに、「おすすめのカレンダーを検索 >>」をクリックします。

f:id:tomo-murata:20171016191927p:plain

おすすめカレンダーの中で「その他」タブをクリックします。

f:id:tomo-murata:20171016192059p:plain

この中に入ると、 xxxx のリソース という項目がありますので、クリックすると全リソースが表示されますので、必要なリソースを登録します。

G Suite での設定は以上です。
ここからは、Zoom Rooms での設定となります。

3.Zoom Rooms にカレンダーサービスを追加する

Zoom Rooms の設定メニューより「カレンダー統合」を選択します。
「Googleカレンダー」を選択すると、どのGoogleアカウントで連携するか聞いてきますので、先ほど作成した連携専用Googleアカウントで連携します。
成功するとこのような感じで、表示されます。(追加したては割り当て数はゼロですね)

f:id:tomo-murata:20171016193047p:plain

4.Zoom Rooms のカレンダーに設定する

ルーム編集の「ルームの設定」に「カレンダー(オプション)」という項目があります。
カレンダーサービスを設定すると、リソース一覧が表示されますので、連携したいリソースを設定します。

f:id:tomo-murata:20171016213652p:plain

5.通知するように設定する

ルーム編集の「ミーティング設定」タブに「次のミーティング警告」という項目があります。

f:id:tomo-murata:20171016213543p:plain

こちらを有効にします。

設定は以上です!!

あとは Zoom Rooms を使っている際に次の会議の10分前になると、ディスプレイ上部に以下のメッセージが表示されます。(邪魔にならないように数秒で消えます)

f:id:tomo-murata:20171016225528j:plain

会議室については、Zoom Rooms よりも便利なサービスを使って管理しております。
このサービスについては、改めて紹介させていただきます。

■ 注意事項

この設定を行うと、コントローラーの Meeting List にも表示されます。
限定公開の場合は予定の名称は伏せられますが、一般公開の場合はそのまま表示されますので、登録の際は注意してください。

まとめ

今回掲載した方法の中には、最近になって実現できるようになったものもあります。

ちなみに、社内で一番反応が良かったのは、AirPlay機能です。
Mac、そして iPhone が多いので、AirPlay はとても便利です!

Zoom Rooms は進化し続け、ますます便利になってきております。
新たな発見があり次第、また公開したいと思います。