WonderPlanet Tech Blog

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

Amazon Echo (Alexa) 用に音声対話クイズのスキルを作成してみた

こんにちはアドバンストテクノロジー部の@y-matsushitaです。
最近はAmazon Echo、Google Home、Clova WAVEと次々に新しいスマートスピーカーが出ていますね。
私も流行りに乗ってAmazon Echo用のAlexaスキルの作成を試してみたのでご紹介します。

作成するAlexaスキル

今回はクラッシュフィーバーのクイズを出題するスキルを試作します。
予め設定した問題を出題しユーザの回答(番号)によって正解か不正解かを返します。
流れとしては以下のような形です。

  1. Alexaから問題を出題
  2. ユーザが1番〜n番までの番号で回答
  3. Alexaから「正解」or「不正解」を返す
  4. 1に戻る(最後まで出題し終えたらAlexaから正解数を発表)

それでは早速始めます。


必要な事前登録

以下への登録が必要です。
developer.amazon.com aws.amazon.com


スキルの作成

開発者ポータルからAlexaのタブを開いて「Alexa Skills Kit」を始めます。
f:id:y-matsushita:20171128174147p:plain:w700

開いたら画面右上の「新しいスキルを追加する」から新規作成します。
f:id:y-matsushita:20171128125454p:plain:w200

スキル情報を入力して保存します。
f:id:y-matsushita:20171201125957j:plain:w700
今回は以下のように設定しました。
・スキルの種類:カスタム対話モデル
・言語:Japanese
・スキル名:クラフィクイズ
・呼び出し名:クラッシュフィーバー
・グローバルフィールド:全ていいえ

対話モデルの生成

次に対話モデルを生成します。
ユーザから受けた命令がどういった意図なのかAlexaが判断できるようにするための設定です。
今回はスキルビルダーから生成します。*1
以下のボタンからスキルビルダーを起動してください。
f:id:y-matsushita:20171128125823p:plain:w250

Intentの追加

Intentsタブの「ADD+」をクリックします。
f:id:y-matsushita:20171128130008j:plain:w700

追加できるIntentはユーザが独自で定義するCustom intentと予め用意されたBuilt-in libraryの2種類があります。
今回は以下のIntentを追加します。

  • Custom intent
     - QuizIntent
     (ユーザがクイズに回答する際に呼び出し)

  • Built-in library
     - AMAZON.RepeatIntent
     (ユーザがクイズの問題を聞き直したい場合に呼び出し)
     - AMAZON.StartOverIntent
     (クイズをスタートする場合に呼び出し)

まずはCustom intentのQuizIntentから追加します。
テキストボックスに「QuizIntent」と入力しCreate intentを押下します。 f:id:y-matsushita:20171128142412p:plain:w700

次にユーザが話す想定の文章を入力します。
ここでは以下のような文章を入力しました。

  • {Answer} 番です
  • {Answer} 番
  • 正解は {Answer} 番

f:id:y-matsushita:20171128144513p:plain:w700
ユーザには回答を番号で答えてもらう想定で、情報を取得したい箇所を{Answer}としています。
注意点として{Answer}の前後には半角スペースが入っていないと後のビルド時にエラーとなってしまうようです。
編集箇所が多くなった後でエラーが発生すると、どこが該当箇所か分からなくなるので注意しましょう。
また、Intentに{Answer}が入った文章を追加するとIntentSlotsに自動でAnswerが追加されます。
Slotには{Answer}で取得できる情報の例を追加します。今回は定義済みのAMAZON.NUMBER(数値情報)がありますので、それを設定してCustom intent の設定は完了です。

あとはBuilt-in libraryのAMAZON.RepeatIntentとAMAZON.StartOverIntentも同様に追加します。
Built-in library のIntentは何も例文を入れなくてもある程度認識してくれますが、ひとまず絶対に認識してほしい文章を入れておきます。今回はAMAZON.RepeatIntentに「もう一回教えて」などのようにクイズの問題を聞き直す文章を入れ、AMAZON.StartOverIntentに「ゲームスタート」とクイズを開始する言葉を入れました。
AMAZON.RepeatIntentとAMAZON.StartOverIntentからは取得したい情報が無いためSlotは設定しません。
まとめると今回は以下のような形で登録しました。

IntentSlot
QuizIntent ・{Answer} 番です
・{Answer} 番
・正解は {Answer} 番
{Answer}
・AMAZON.NUMBER
AMAZON.RepeatIntent もう一回教えて
もう一度教えて
無し
AMAZON.StartOverIntent ゲームスタート 無し

最後まで完了すると以下のようにIntentsとSlot Typesが並びます。
f:id:y-matsushita:20171128150846j:plain:w300

ビルド

Intentの登録が完了したらモデルをセーブして「Build Model」を押下します。
f:id:y-matsushita:20171128145837p:plain:w200
問題なく完了すれば以下のような表示がされます。
f:id:y-matsushita:20171128145928p:plain:w600

ビルドで失敗してしまった場合は以下が原因でエラーが出ていることが多かったので見直してみてください。

エラー内容確認する箇所
Error building interaction model
A sample utterance for a slot in the interaction model is invalid
設定した{Answer}の前後に半角スペースがあるかどうか
Error building interaction model Bad request {Answer}にAMAZON.NUMBERのSlotTypeを追加しているかどうか

ビルドが完了したら画面右上の「Configuration」から設定画面へ戻ります。
f:id:y-matsushita:20171128151132p:plain:w100


AWS Lambda

ここから先はAWS Lambdaで編集します。
AWS LambdaでAlexaから受け取ったIntentをもとにユーザに返すべき発言をAlexaを通して返します。

Alexa用のLambda関数を作成

Lambdaの関数の作成から「alexa-skill-kit-sdk-factskill」のテンプレートを選びます。
f:id:y-matsushita:20171128151842p:plain:w700

適当な関数名とロールを入力して作成します。
f:id:y-matsushita:20171128151944p:plain:w700

トリガーにAlexa Skils Kitを追加します。
f:id:y-matsushita:20171128152022p:plain:w700
追加すると以下のようになります。
f:id:y-matsushita:20171128152220j:plain:w400

コードを書き換え

デフォルトのコードを以下に書き換え保存します。

"use strict";
const Alexa = require('alexa-sdk');
// ステートの定義
const states = {
  QUIZ: '_QUIZMODE',
  START: "_STARTMODE"
};

// クイズ内容の定義
const questions = [
  { 'q' : 'クラッシュフィーバーの略称は? 1.クラフィ、2.クラッシュ',  'a' : '1' },
  { 'q' : 'ワンダープラネットの略称は? 1.ダープラ、2.ワンプラ、3.ワンダー',  'a' : '2'},
  { 'q' : 'クラッシュフィーバーの通貨単位は次のうちどれ? 1.ゼニー、2.ゴールド、3.ビット',  'a' : '3'},
  { 'q' : '存在しないタイプはどれ? 1.魔法、2.体力、3.バランス',  'a' : '1'},
  { 'q' : '果実を使うと上がるのはどれ? 1.レベル、2.バグ、3.ステータス',  'a' : '3'},
  { 'q' : 'クエストに参加するのに必要なものは次のうちどれ? 1.スタミナ、2.ビット、3.エナジー',  'a' : '3'},
];
var languageString = {
    "ja-JP": {
        "translation": {
            "WELCOME_MESSAGE": "クラフィクイズへようこそ。 ",
            "HELP_MESSAGE": "正解だと思う番号を回答してください。",
            "START_MESSAGE": "ゲームを始める場合は「ゲームスタート」と言ってください。 ",
            "ANSWER_CORRECT_MESSAGE": "正解。 ",
            "ANSWER_WRONG_MESSAGE": "残念、不正解。 ",
            "TELL_QUESTION_MESSAGE": "第%s問。 ",
            "GAME_OVER_MESSAGE": "全ての問題が終わりました。あなたの点数は%s点でした。遊んでくれてありがとう。 ",
            "UNHANDLED_MESSAGE": "すみません、よく聞きとれませんでした。"
        }
    }
};

exports.handler = function(event, context, callback) {
  var alexa = Alexa.handler(event, context);
  alexa.resources = languageString;
  alexa.registerHandlers(handlers, startStateHandlers, quizHandlers);
  alexa.execute();
};

var handlers = {
  'LaunchRequest': function () {
    this.handler.state = states.START;
    this.emitWithState("StartGame");
  },
  "AMAZON.StartOverIntent": function() {
      this.handler.state = states.START;
      this.emitWithState("StartGame");
  },
  'AMAZON.HelpIntent': function () {
    this.emit(':ask', this.t("HELP_MESSAGE") + this.t("START_MESSAGE"));
  },
  'Unhandled': function () {
    var speechOutput = this.t("UNHANDLED_MESSAGE") + this.t("START_MESSAGE");
    this.emit(":ask", speechOutput, speechOutput);
  }
};


// ゲーム開始ステート
var startStateHandlers = Alexa.CreateStateHandler(states.START, {
    "StartGame": function () {
      this.handler.state = states.QUIZ; // クイズ回答ステートをセット
      this.attributes['advance'] = 1;   // 進行状況をセッションアトリビュートにセット
      this.attributes['correct'] = 0;   // 正解数を初期化
      var message = this.t("WELCOME_MESSAGE") + this.t("HELP_MESSAGE") + this.t("TELL_QUESTION_MESSAGE", "1") + questions[0].q;
      var reprompt = this.t("TELL_QUESTION_MESSAGE") + questions[0].q;
      this.emit(':ask', message, reprompt); // 相手の回答を待つ
      console.log(message);
    }
});


// クイズ回答ステート
var quizHandlers = Alexa.CreateStateHandler(states.QUIZ, {
  'QuizIntent': function() {

    // スロットから回答を参照
    var usersAnswer = this.event.request.intent.slots.Answer.value;
    if(!usersAnswer){
      this.emitWithState("Unhandled");
    }

    var resultMessage;
    if(questions[this.attributes['advance']-1].a == usersAnswer){
        resultMessage = this.t("ANSWER_CORRECT_MESSAGE")     //正解
        this.attributes['correct'] ++;
    }else{
        resultMessage = this.t("ANSWER_WRONG_MESSAGE")     //不正解
    }

    if(this.attributes['advance'] < questions.length){
        // まだ問題が残っている場合
        var nextMessage = this.t("TELL_QUESTION_MESSAGE", this.attributes['advance']+1) + questions[this.attributes['advance']].q;
        this.attributes['advance'] ++;
        this.emit(':ask', resultMessage+nextMessage, nextMessage);
    }else{
        // 全ての問題が終了した場合
        var endMessage = this.t("GAME_OVER_MESSAGE", this.attributes['correct'])
        // スキルを初期状態に戻すためステートをリセット
        this.handler.state = '';
        this.attributes['STATE'] = undefined;
        this.attributes['advance'] = 0;
        this.emit(':tell', resultMessage + endMessage, endMessage);
    }
  },
  "AMAZON.RepeatIntent": function() {
    var nextMessage = this.t("TELL_QUESTION_MESSAGE", this.attributes['advance']) + questions[this.attributes['advance']-1].q;
    this.emit(':ask', nextMessage, nextMessage);
  },
  'Unhandled': function() {
    var reprompt = this.t("UNHANDLED_MESSAGE") + this.t("HELP_MESSAGE");
    this.emit(':ask', reprompt, reprompt);
  }
});

このスキルでは主にstartStateHandlersとquizHandlersの2つのステートで状態を管理しています。
まずスキル起動直後はAlexaからAMAZON.StartOverIntentが来るのを待ちます。ユーザが「ゲームスタート」と言うとAMAZON.StartOverIntentが発生するのでstartStateHandlersで初期化を行い、ステートをquizHandlersへ移します。AMAZON.StartOverIntent以外(ユーザが「ゲームスタート」と言っていない)の場合は、誘導用のメッセージを返します。

quizHandlersではユーザの発言した回答の番号がthis.event.request.intent.slots.Answer.valueで取得できるので、questionsのaと比較し正否の判定を行います。またAMAZON.RepeatIntentが呼ばれている場合は再度問題文を読み上げます。もし何にも引っかからない場合はUnhandledが呼ばれ、ヘルプ用のメッセージを表示してユーザを誘導します。
正否判定の後には問題数と進行状況を比較し、クイズを続けるか、終えるかを判断しています。クイズが続く場合はthis.emitを:askにして再度Alexaから問いかけを行い、終了する場合はthis.emitを:tellにしてクイズの正解数を読み上げて対話を終了します。

ここまででコードの保存が完了したらLambdaの画面右上のARNをコピーします。
以上でLambda側の操作は完了です。
f:id:y-matsushita:20171128152558p:plain:w700

ARNの設定

Alexaの開発者コンソールに戻り、先ほどコピーしたARNを入力します。
他にも設定項目がいくつかありますが、今回はデフォルトのままでOKです。
f:id:y-matsushita:20171128173451p:plain:w700

入力後「次へ」を押して問題なければ作成したスキルでテストが可能になります。

シミュレータでのテスト

画面をスクロールするとサービスシミュレータという項目があります。
色々入力してどういう結果が返ってくるかWEB上でテストしてみましょう。
問題なければ「ゲームスタート」と送るとクイズが始まるはずです。
f:id:y-matsushita:20171128173712p:plain:w700
何かおかしな挙動がみつかれば対話モデルやLambdaのプログラムを修正していく流れになります。
サービスリクエストに使われたJSONはそのままLambdaに渡すとLambda側のみでテストすることも可能です。

実機でのテスト

シミュレータでのテストで問題が無ければ、いよいよ実機でテストを行います。
Alexaの開発者アカウントと実機テストをする端末のアカウントが同じであれば、すでに実機テストが可能です。
また「Skills Beta Testing」を使ってテストユーザとして招待する形で実機テストも可能です。
f:id:y-matsushita:20171201141213p:plain:w200
「Skills Beta Testing」を有効化するには、「公開情報」と「プライバシーとコンプライアンス」を記入していきます。
この作業をしても申請をしなければ一般公開されないのでご安心ください。

公開情報を入力

公開情報のタブを開き、必要事項を記入していきます。
全て入力する必要がありますが、申請しないのであれば適当に入力してもテストは可能です。 f:id:y-matsushita:20171201152450p:plain:w700
今回は以下のように設定しました。
・カテゴリー:Games, Trivia & Accessories
・サブカテゴリー:Games
・テストの手順:任意の文書
・国と地域:国と地域を選択する→Japan
・スキルの簡単な説明:任意の文書
・スキルの詳細な説明:任意の文書
・サンプルフレーズ:任意の文書(ウェイクワードなどを記載)
・キーワード:任意のキーワード (省略可)
・アイコン:108x108と512x512の画像を設定

プライバシーとコンプライアンスを入力

プライバシーとコンプライアンスのタブを開き、該当する項目にチェックを入れます。
f:id:y-matsushita:20171201153810p:plain:w700

「公開情報」と「プライバシーとコンプライアンス」を入力して問題なければ、
以下のボタンが押せるようになり、実機でのベータテストが可能になります。
f:id:y-matsushita:20171201154801p:plain:w200

テストユーザを登録

スキルを動かしたいユーザのAlexaアカウントのメールアドレスを入力します。
f:id:y-matsushita:20171201160501j:plain:w700

登録したメールアドレスの受信ボックスを確認すると以下のような文面のメールが確認できます。
f:id:y-matsushita:20171201160928j:plain:w500
リンクが2つあるのが確認できますが、下の「JP customers」のリンクをクリックしてください。
Alexaのスキル管理画面は英語版の「.com」と日本語版の「.co.jp」があります。
上のリンクをクリックすると英語版として認識されるため日本語のAlexaスキルが実行できない恐れがあります。

リンク先ではスキルの設定ができるので「有効にする」をクリックしましょう。
f:id:y-matsushita:20171201161639p:plain:w300

有効化すると遂にスキル一覧に作成したスキルが出てきます!
f:id:y-matsushita:20171201162043p:plain:w700

Alexaに呼びかけてみよう!

以上の手順を終えて呼びかけると、他の公開されているスキルと同様に反応してくれるはずです。 *2
手順が長くなりましたが、なんとかAlexaに独自のスキルを追加することができました。
実機のAlexaに話しかけて反応を楽しみましょう!
f:id:y-matsushita:20171201124024j:plain:w700

参考

*1:2017/11/27時点でβ版のため、今後のアップデートで設定内容が大きく変わる恐れがあります。

*2:Alexaに「すみません、なんだかうまくいかないみたいです。」と言われてしまう場合は、ウェイクワードを変えてみましょう。
ウェイクワードによっては起動しづらいことがあるようです。今回作成したスキルもウェイクワードを「クラフィクイズ」にしていた際、認識が上手くされないことがありました。

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モデルが作成できたのは、かなり凄いです!
試すのに時間はかからないので一度チャレンジしてみてはいかがでしょうか。