WonderPlanet Tech Blog

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

Google Natural Language API を活用した誰でも出来る!自然言語処理!

こんにちはアドバンストテクノロジー部の@y-matsushitaです。
今回は高度な知識や大量の教師用データが不要で始めることができる、
Google Natural Language APIを使った感情解析を試してみたのでご紹介します!

Google Natural Language APIとは

Googleが提供する自然言語処理の機械学習モデルです。テキストの構造と意味を解析できます。
SNSやECサイトに寄せられたコメントから製品に対するセンチメント(感情)を把握したり、顧客満足度を分析したりすることができます。

動作サンプル

WEB上で動かせるサンプルがあります。
ひとまず「Try the API」の箇所に任意のテキストを入れて試してみましょう。
現在は下記の3つ、Entities, Sentiment, Syntaxが日本語で利用可能です。
(Categories(テキストのカテゴリ分け)のみ2017/10/17時点で未対応) cloud.google.com

Entities

f:id:y-matsushita:20171017161446p:plain:w600
エンティティ分析:
指定されたテキストに既知のエンティティ(著名人、ランドマークなどの固有名詞、レストラン、競技場などの普通名詞)が含まれているかどうかを調べます。
エンティティ分析を行うには analyzeEntities メソッドを使用します。

Sentiment

f:id:y-matsushita:20171017161556p:plain:w600
感情分析:
指定されたテキストを調べて、そのテキストの背景にある感情的な考え方を分析します。
執筆者の考え方がポジティブか、ネガティブか、ニュートラルかを判断します。
感情分析を行うには analyzeSentiment メソッドを使用します。

Syntax

f:id:y-matsushita:20171017161652p:plain:w600
構文解析:
指定されたテキストから言語情報を抽出し、一連の文とトークン(通常は単語の境界)に分解します。
構文解析を実行するには analyzeSyntax メソッドを使用します。

感情分析

上記3つの中で感情分析に注目します。
感情分析はテキストをネガティブなものとポジティブなものに分類して、 ユーザが何に不満を持っていて何に満足しているかを分析することができます。

f:id:y-matsushita:20171017163030p:plain:w700

Entire Document Score Magnitude
全体 0 1.5
この商品使い勝手は良いしコスパも良くて最高! 0.8 0.8
ただしデザインがダサいしカラーバリエーションも少なすぎ -0.7 0.7

上記ではEntrieDocumentの全体のScoreが0となっています。
Scoreは-1.0〜1.0までの値で感情の分析を行い、ポジティブなものほど1.0に近くなります。
逆にネガティブに近づくと-1.0に近くなります。なのでこのテキスト全体では平均的な感情に近いことになります。

ただし各文節ごとの感情をみると、ある観点にはポジティブな感情を出しているが、別の観点にはネガティブな感情を出していることがわかります。
このように文節ごとに、ユーザが何に高評価を出しており、何に不満を持っているか、分析することもできます。

またMagnitudeは感情の振れ幅を示します。 EntrieDocumentのMagnitudeは1.5なので振れ幅としてはそれなりにあります。(初期は0) つまりMagnitudeによってポジティブな感情とネガティブな感情が混在したテキストという解析結果も得られます。


Google Natural Language APIをPythonから呼び出してみる

前置き長くなりましたが、WEBのサンプルであったNatural Language APIを、
Pythonから呼び出してテキストの感情分析を行ってみます。使用環境はPython3.6.1です。
Google Cloud Platformの登録が済んでいない場合は済ませておいてください。
Cloud Natural Language API  |  Google Cloud Platform

Google Natural Language APIの課金について

感情分析の場合、1,000件辺り$1ですが、5,000件までは無料で利用可能です。(2017/10/17時点)
無料の範囲内でも、かなりの回数試すことができます!
詳細は下記をご確認ください。
料金  |  Google Cloud Natural Language API ドキュメント  |  Google Cloud Platform

1. GCPの「APIとサービス」から有効化

ダッシュボードの「APIとサービスの有効化」からNatural Language APIを探して有効化させます。 f:id:y-matsushita:20171017170556p:plain:w700

有効化すると以下のようにダッシュボードで確認できます。 f:id:y-matsushita:20171017170714p:plain:w800

2. API キーを発行

APIキーを使っての呼び出しを試してみます。
「認証情報」から「APIキー」を選択してキーを発行します。
リクエストを受け入れるIP addressesに使用するサーバのIPなどを入力して外部から使われないようにしておきます。
f:id:y-matsushita:20171017171025p:plain:w800
発行したAPIキーは外部に公開されないように注意してください。

APIキーを使って感情分析の結果を取得する

gcp_sentiment.py

import sys
import requests

def main(content, access_token):
    url = 'https://language.googleapis.com/v1/documents:analyzeSentiment?key={}'.format(access_token)
    header = {'Content-Type': 'application/json'}
    body = {
        "document": {
            "type": "PLAIN_TEXT",
            "language": "JA",
            "content": content
        },
        "encodingType": "UTF8"
    }
    response = requests.post(url, headers=header, json=body).json()
    print(response)

if __name__ == '__main__':
    main("".join(sys.argv[1:]), "取得したAPIキーを設定")

上記、コードを実行します。

$ python gcp_sentiment.py "この商品使い勝手は良いしコスパも良くて最高!ただしデザインがダサいしカラーバリエーションも少なすぎ"

結果は以下のようなJSON形式で取得できます。 文節ごとの感情分析のスコアと総合的な感情分析のスコアが取得できます。

{
    "documentSentiment": {
        "magnitude": 1.5,
        "score": 0
    },
    "language": "ja",
    "sentences": [
        {
            "text": {
                "content": "この商品使い勝手は良いしコスパも良くて最高!",
                "beginOffset": 0
            },
            "sentiment": {
                "magnitude": 0.8,
                "score": 0.8
            }
        },
        {
            "text": {
                "content": "ただしデザインがダサいしカラーバリエーションも少なすぎ",
                "beginOffset": 66
            },
            "sentiment": {
                "magnitude": 0.6,
                "score": -0.6
            }
        }
    ]
}

結果からdocumentSentimentのScoreのみを取得したい場合は、 以下のような形でresponseから取得することができます。

response = requests.post(url, headers=header, json=body).json()
score = response['documentSentiment']['score']

 


Google Natural Language APIが弱い点と対処法

一般的にはネガティブな表現として扱われるものは当然APIでもネガティブな方へ寄ります。
具体的には弊社の「クラッシュフィーバー」や「バグ上げ」*1などがそれにあたります。


・「クラッシュフィーバー」→「クラッシュ」
・「バグマ」、「バグ上げ」→「バグ」

「ついにバグがMAXになった!クラッシュフィーバープレイ中。」
 感情分析のスコア:-0.4
f:id:y-matsushita:20171017185935p:plain:w600

{
    "documentSentiment": {
        "magnitude": 1.3,
        "score": -0.4
    },
    "language": "ja",
    "sentences": [
        {
            "text": {
                "content": "ついにバグがMAXになった!",
                "beginOffset": 0
            },
            "sentiment": {
                "magnitude": 0.7,
                "score": -0.7
            }
        },
        {
            "text": {
                "content": "クラッシュフィーバープレイ中。",
                "beginOffset": 60
            },
            "sentiment": {
                "magnitude": 0.1,
                "score": -0.1
            }
        }
    ]
}

これらのような単語が含まれることが予測される場合は、
以下のように予め当たり障りの無い単語に置換してからAPIを活用すると結果に悪影響を与えずに済みます。

gcp_sentiment.py

import sys
import re
import requests

def main(content, access_token):

    # 処理前に整形(APIに誤った解釈をされないように置換)
    content = re.sub('バグ', "限界突破", content)
    content = re.sub('クラッシュフィーバー', "クラフィ", content)

    url = 'https://language.googleapis.com/v1/documents:analyzeSentiment?key={}'.format(access_token)
    header = {'Content-Type': 'application/json'}
    body = {
        "document": {
            "type": "PLAIN_TEXT",
            "language": "JA",
            "content": content
        },
        "encodingType": "UTF8"
    }
    response = requests.post(url, headers=header, json=body).json()
    print(response)

if __name__ == '__main__':
    main("".join(sys.argv[1:]), "取得したAPIキーを設定")

以下は整形した後に取得したレスポンスです。

{
    "documentSentiment": {
        "magnitude": 1.4,
        "score": 0.1
    },
    "language": "ja",
    "sentences": [
        {
            "text": {
                "content": "ついに限界突破がMAXになった!",
                "beginOffset": 0
            },
            "sentiment": {
                "magnitude": 0.6,
                "score": 0.6
            }
        },
        {
            "text": {
                "content": "クラフィプレイ中。",
                "beginOffset": 66
            },
            "sentiment": {
                "magnitude": 0.3,
                "score": 0.3
            }
        }
    ]
}

置換前後の結果比較

原文 素で渡した場合 置換して渡した場合
・バグ→限界突破
・クラッシュフィーバー→クラフィ
ついにバグがMAXになった! -0.7 0.6
クラッシュフィーバープレイ中。 -0.1 0.3

 


扱えるメソッドまとめ

Methods
analyzeEntities POST /v1/documents:analyzeEntities
著名人、ランドマークなどの固有名詞が含まれていないかどうかを調べて、それらのエンティティに関する情報を返す
analyzeEntitySentiment POST /v1/documents:analyzeEntitySentiment
エンティティ分析と感情分析の両方を組み合わせたもの。テキスト内エンティティの感情(ポジティブかネガティブか)を返す
(※日本語非対応2017/10/17時点)
analyzeSentiment POST /v1/documents:analyzeSentiment
テキストの感情(ポジティブかネガティブか)を返す
analyzeSyntax POST /v1/documents:analyzeSyntax
テキストの言語情報を抽出し分解し構文解析した結果を返す
annotateText POST /v1/documents:annotateText
analyzeSentiment、analyzeEntities、analyzeSyntaxが提供するすべての機能をまとめて1回の呼び出しで返す

*1:クラッシュフィーバーでは同じユニットを合成することをバグを上げるといいます。バグが上がるとクエストで報酬が増えるなどの特典があります。

Robinを利用してゴースト会議をなくそう

こんにちは、アドバンストテクノロジー部の長谷川です。
今回はワンダープラネットで利用している、会議室予約システムの Robinについてご紹介していきます。

robinpowered.com

Robinとは

Robin は会議室の予約や管理するためのサービスで G Suite、Office365、Exchange などのスケジューラとの連携もできます。 Robin を利用することで、予約した会議室の利用状況が可視化できるため、より効率的な会議室の運用が可能になります。

Robinの導入背景

今まで、会議室の予約にはGoogleカレンダーと連携して利用するrakumoカレンダーを利用していたのですが、各会議室に Zoom を導入したことで会議室の利用頻度が上がり以下の問題がありました。

問題点

・ 会議が予定より早く終わったが、予約をしたままの状態になっている
・ 予定していた会議がキャンセルになったときや、仮押さえの予定がいらなくなたときに、予約が残ったままになっている
・ 会議が終了時間になっても終わらない      
・ 入る会議室を間違える

そのためムダな「空予約」を生み、使いたい時に使えないという 非常に効率の悪い会議室の運用になっていました。

これらを改善するために導入したものが Robin です。

用意するものはタブレットだけ。 使い方も簡単!

会議開始時

会議が始まる前は

  • ミーティングタイトル
  • 会議時間

が表示されます。

会議の開始時に 「Start early」 もしくは 「Check in」 をタップして会議を始めます。

開始10分前より Start early と表示されます

f:id:hasegawat:20171117203222p:plain

開始時間以降は Check in と表示されます

f:id:hasegawat:20171117203316p:plain

会議終了時

会議中は画面全体が赤く表示されているので 会議室の利用の有無が外からでも一目でわかります。

会議の終了時に 「End Meeting」 をタップします。

f:id:hasegawat:20171117203245p:plain

基本的な操作はこれだけです。 この操作を行うと事前に予約をしていたスケジュールが変わります。

20:30〜21:00で予約

f:id:hasegawat:20171117203342p:plain

実際は20:25開始、20:50終了

f:id:hasegawat:20171117203413p:plain

タブレットで操作した時間がカレンダーにリアルタイムに反映され、空いた時間が利用できるようになるのでムダな予約を減らすことができるようになります。

ワンダープラネットでは各会議室の中と外側の壁にタブレットを設置していて、会議室に入る前は外側、会議が終わり出てくるときは中のタブレットと使い分けています。また、自分が予約した会議室や会議状況が外側からもわかりやすくなっています。

f:id:hasegawat:20171117171147p:plain

他にも機能は色々とあるので紹介していきます。

空き会議室の確保

利用したい時間をタップするだけで、自動的にカレンダーに反映され会議室を確保することができます。

f:id:hasegawat:20171117203605p:plain

時間の延長

こちらも利用したい時間をタップするだけです。

f:id:hasegawat:20171117203625p:plain

会議室を予約なしで利用する時や時間を延長して利用する時もタブレットだけで簡単にできるようになります。

空き会議室の確保や時間の延長は後の予定が空いていることが前提になりますが、 後に予定が入っている場合も後の会議開始時間以上は予約が取れないようになっていて、会議がバッティングすることはないのでご安心を!

今後のスケジュール

現在利用中の会議室の今後のスケジュール、他の会議室の利用状況もタブレットから見ることができます。

「Today's schedule」 をタップします。

f:id:hasegawat:20171117203648p:plain

画面右側に、現在利用中の会議室の今後の予定が表示されます

f:id:hasegawat:20171117203707p:plain

他会議室の利用状況

現在利用している会議室を延長したいけど、予定が入っていて他の会議室に行かないと。でもどこが空いているのだろう…

といった状況にもタブレットから確認ができます。

「Find another space」 をタップします。

f:id:hasegawat:20171117203727p:plain

利用可能もしくはもうすぐ利用できる会議室の一覧が表示されます。

f:id:hasegawat:20171107133310p:plain

また、管理画面から以下の機能が設定できるようになります。

自動削除機能

Check inしないとスケジュールを自動で削除してくれる機能で、予約したけど使わずに解放もされないといった空き会議室状態を回避してくれます。

 ・ 「Abandoned meeting protection」「Enabled」にすると自動削除機能が有効になります。
 ・ 「Abandoned Threshold」 では会議開始時間から何分 Check in をしなかったらスケジュールから自動で削除するのか設定できます。

下記の設定だと会議開始時間から15分以内に Check in をしないとスケジュールから削除され空き状態になります。

f:id:hasegawat:20171107142421p:plain

繰り返し登録されたスケジュールの削除機能

毎週の定例ミーティングなどは毎回予約するのが面倒くさいので、繰り返しでスケジュールを登録することもあるかと思います。ただ、今はその定例ミーティングはやらなくなったが予約を削除していない場合、自動削除機能があるとはいえ削除されるまでは毎週予約された状態になってしまいムダな空き時間ができてしまいます。

そのような状態でも下記の設定をすることで、連続で自動削除されると、以降の繰り返しスケジュールを削除してくれます。

f:id:hasegawat:20171107191232p:plain

上記の設定では3回連続で自動削除されると以降の繰り返しスケジュールが削除されます。

ミーティングタイトルのマスク機能

ミーティングタイトルにマスクをかけることもできます。管理画面から 「Mask meeting titles」「Enabled」 でマスク機能が有効になります。

※Googleカレンダーで「非公開」としてスケジュールを登録すると設定の有無に関わらずミーティングタイトルにマスクがかかります。

f:id:hasegawat:20171107200519p:plain

f:id:hasegawat:20171117203804p:plain

マスクをかけると全てのミーティングタイトルが Reserved と表示されます。

f:id:hasegawat:20171117203818p:plain

まとめ

導入してから2ヶ月程が経ちましたがゴースト状態の会議室がなくなり、かなり効率的に会議室を運用できています。 操作も簡単なので、社内でもすぐに使いこなせて今ではなくてはならない存在になっています。 この記事を機に同じ問題を抱えている皆様の会社にも、導入を検討してみてはいかがでしょうか?

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系のバグは改善しています。