ラベル watson の投稿を表示しています。 すべての投稿を表示
ラベル watson の投稿を表示しています。 すべての投稿を表示

2016年2月1日月曜日

Pepper に Watson を組み込み、コグニティブロボット化

SoftBank(Aldebaran)のPepperの頭脳にIBMのWatsonを導入させ知性を進化をさせる、という記事を見かけたがどのような仕組みで連携させているのだろうか。自前でも2つのサービスを繋げ、Pepperを高度なシナリオや会話ができるコグニティブロボットへと変身させてみる。


◆ 事前に用意するもの
(Choregraphe)
Pepperの実機を用意するのは難しいだろう。しかし、SDKであるChoregraphe(無料)があれば一部制約はあるがバーチャルロボットを画面内で動かしながら開発することができる。


(IBM Bluemix アカウント)
Watsonサービスを使うためにはBluemixでアカウントを取得する必要がある(30日間は無料である)。
複数のWatsonサービスがあるが、今回はその中で次の2つのサービスを利用する。

 - Natural Language Classifier(NLC)
機械学習とニューラルネットワークを使った分類器サービスである。

 - Dialog ※Conversation というサービスに変わっている
ChoregrapheのSDKで使えるALDialog/QiChatではない。Watsonサービス群の一つであるDialogである。
自然言語ソフトウェアエージェント構築のためのXMLを応用したマークアップ言語としてAIML(Artificial Intelligence Markup Language)が知られているが、そのIBM拡張だろう。
質問と回答の問答集をXMLファイルで作成するだけで対話形式のサービスを作成できる。
簡単なチャットボットのアプリケーションなら力技ですぐに作れるだろうか、と思ったがすぐに思い直した。

例えば、
表記揺れ: "引っ越し"、"ひっこし"、"引越"、"引越し"、
同義語:  "引っ越す"、"転居"
綴り誤り: "引き越し"、"引 越"
用言活用(動詞、形容詞など): "遊ぶ"、"遊んで"

さらに異字体や英数漢字が混ざった言葉はどうするか。
正規表現で対応するか?かなりハードルが高いことが想像つくと思う。
(参考までにこういった人工無脳チャットボットの作り方もある)

Dialogにはifなどの条件式を入れた処理フローを挿入できるようであるが、自分は言葉の揺らぎを吸収するデータベースとしての活用に期待が持てた。モデルとコントローラを分けるという意味でもよいだろう。

ただ、触ってみる限り手を叩いて喜ぶほど嬉しい効果はまだ見られないようだ。
しかし、どのbluemixサービスもそうだが、更新が非常に早いため、今後の期待は持てる。

正式なドキュメントがないため日本語文章のカバレッジ範囲の詳細は分からないが、期待する動作が未対応であっても、独自にカスタマイズできる要素を活用することでで意図した動きをさせることは可能そうである。
XML内に記載できるタグとして用意されているentity, conceptあたりを利用するのだろう。

entity
 複数の語を一つの変数で代替
 (例) サイズ: 小さい、中くらい、大きい

concept
 同義語の定義
 (例) 小さい、スモール、ちっちゃい



◆ 実現したいこと
ありとあらゆる、デジタル機器のサービスサポート受付支援ロボットを作成する。

「スマホの電源が入らない」
「マウスが動かない」
「WiFiがつながらない」

などの質問に対話形式で回答を導く。



◆ 設計概要

                        質問
                         ↓ 
                      +-----+
                      | NLC |
                      +-----+
                         ↓
+---------+  +---------+  +---------+  +---------+
| Dialog1 |  | Dialog2 |  | Dialog3 |  | Dialog4 |
+---------+  +---------+  +---------+  +---------+


質問を受けつけたのち、NLCで質問の意図を抽出し、
そのインテントを元に専用のDialogへ流す。

例えば、先の会話例文だと下の動きになる。

      質問文            NLC           Dialog
「電源が入らない」     ⇒ 電源   ⇒ 電源トラブル解決問答集
「マウスが動かない」   ⇒ マウス ⇒ マウストラブル解決問答集
「WiFiがつながらない」 ⇒ WiFi   ⇒ WiFiトラブル解決問答集


最初のポイントはNLCである。
種々の会話に対応するチャットシステムを構築することは難しい。
そこで、特定の会話に特化したDialogを細分化して作っておき、
どのDialogへ受け流すべきかをNLCに判断させるわけである。
この構成にしておくと頭脳のスケールも容易にできる。

そしてDialogだが、先の電源トラブル回答問答集であれば、このようになるだろう。
「電源が壊れたんだけれどどうすりゃいい?」
「それはパソコンですか、モバイル機器ですか」
「パソコンだけど」
「Windows機ですか、Macですか」


基本は以上だが、「バカ、アホ、マヌケ」のようないたずら会話が来ることを想定し、
これらを"悪口"として、NLCに学習させておくといいかもしれない。
悪口を言われたらそれにふさわしい返答をPepperがするときっと驚かれるだろう。


NLCからDialogまでの間にデータベースを挟ませてもいいだろうか。

                      +-----+
                      | NLC |
                      +-----+
                         ↓
                      +-----+
                      | DB  |
                      +-----+

NLCが返してくるインテントと結びつけるDialogをDBで管理するためである。
それ以外の用途として、すべての質問に対話形式で答える必要がない場合もあるだろうと考えたためである。
必ず対話形式に持っていかなくとも、あるインテントに対していきなり回答を出す、またはURL等を示し別サイトへ誘導する方が親切な場合がある。
Dialogへ流さすまでもない一言で終わる回答などを入れておくというわけである。



◆ Watson事前準備
(NLC学習セットの用意)
想定される問と、そこから抽出したいインテントをペアにした学習させるためのcsvファイルを作る。

"スマホの電源が入らない","電源"
"マウスが動かない","マウス"
"WiFiがつながらない","WiFi"
~snip~

トレーニングデータの各テキストは1024文字以下である必要がある。
全レコードは5件以上、15000件以下である必要がある。

NLCを使った別アプリを作成したことがあるのでこちらも参考になるだろう。


(Dialogの作成)
~XMLファイルの用意~
公式サイトにある、pizzaのサンプル用xmlと同じように作れば良い。
また、APIリファレンスはこちら。
https://watson-api-explorer.mybluemix.net/apis/dialog-v1
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/dialog/api/v1/


~環境変数の設定~
$はプロンプトである。
$ url="https://gateway.watsonplatform.net/dialog/api"
$ username=“*****"
$ password=“*****“
$ file=“power.xml"
$ name=“power"


~ファイルのアップロード~
$ curl -k -u ${username}:${password} \
-X POST \
--form file=@${file} \
--form name=${name} \
"${url}/v1/dialogs"

レスポンスとしてdialog_idが返ってくる。
$ dialog_id=“*****"

~アップロードしたdialogと対応言語の確認~
以下のRESTでもdialog_idが確認できる。
またこのレスポンスとしてに対応している言語パックの情報も返ってくる。
$ curl -k -u ${username}:${password} \
-X GET \
"${url}/v1/dialogs"


以下はChoregrapheのPythonボックスで操作する。
操作手順としてcurlで書いているだけである。
~会話の開始~
$ input=""
$ curl -v \
-X POST \
-d "input=${input}" \
-u ${username}:${password} \
"${url}/v1/dialogs/${dialog_id}/conversation"

レスポンスとして会話の最初の応答(電源が入らないのはどちらの機器ですか、~など)と、client_id、conversation_idが返ってくる。

$ client_id=“*****"
$ conversation_id=“*****"

~会話の継続~
$ input=“パソコンです"
$ curl -v \
-X POST \
-u ${username}:${password} \
-d "conversation_id=${conversation_id}" \
-d "client_id=${client_id}" \
--data-urlencode "input=${input}" \
"${url}/v1/dialogs/${dialog_id}/conversation“

この処理を繰り返し会話をしていけばよい。
セッションの保持期間の明示的な記載はなかった。



◆ プログラム書く前の準備
(pythonモジュールの導入)
・requests
Watsonサービスは全てRESTで操作できる。
ChoregrapheではPythonを利用する。PythonでREST操作するにはrequestsモジュールが便利だろう。

$ sudo easy_install pip
$ sudo pip install requests

$ mkdir -p /Users/my_user/Desktop/pepper/watson/lib
$ cp -r /Library/Python/2.7/site-packages/requests
$ cp -r /Library/Python/2.7/site-packages/requests ./lib/


・sqlite3
先に少し書いたように、DBを挟むならsqliteに限らず準備しておく。
$ mkdir db
$ sqlite3 db/watson.sqlite3
$ create table maps(id integer primary key, key text, value text);
.table
.exit



◆ コード例
Choregraphe上のwatsonを利用したボックス部分だけを載せる。
特定の会話がきたらタブレットの表示を変える、など面白くなく要素はたくさんあるだろう。そこは各自工夫してほしい。

(NLC on Choregraphe)


(Dialog on Choregraphe)



◆ 改善点
よりAI的にするために手を入れる箇所は山ほどあるだろう。
思いついたものをいつか加えるための備忘録として残しておく。

(別技術との連携)
・Word to Vector
  単語の類似性の判断に使われる技術である。これはまさにNLCがやっていそうなことであるが、独自にカスタマイズする場合は一歩下がったレイヤーで触る必要があるだろう。

・Learning to Rank
  回答候補のランキング付けに使えそうである。
  Watsonサービスに、Retrieve&Rankというサービスがあるのでそれを使うと便利かもしれない。

・TF-IDF(Term Frequency Inverse Document Frequency)
  用語頻度と逆文献頻度を導入したい場合にこのアルゴリズムを使うといいだろう。


(フィードバック機能)
間違った応対を繰り返したくはない。
そこで、求められる解と違った場合は、そのQ&Aをバックエンドで記録し、学習データの修正に役立てる必要あるだろう。

満足させられなかった回答をどう拾うかだが、例えば、会話の最後にそれを素直に”はい"、"いいえ”で聞くのが確実だろうか。


(突然の例外)
突然怒り出す人もいるだろう。
「ロボットと会話したくねぇ。さっさと人を出せ」
そんな中でのんきに会話を続けるべきではないだろう。
そこで感情分析も並行して実施し、"怒り"のインテントがつけば、
「お待ちください、代わります」と引き下がるような例外処理を加えるのもいいだろう。


(ドローンとの連携)
これは単純に面白そうなため自分がやりたいだけである。
Pepperが手を挙げるとドローンが現れて、周りをクルクルSPのように巡回し始める。
ジョジョのアニメで言うところのスタンドみたいなものか。
「あいつを攻撃せよ」
と言えばドローンが目の前の誰かめがけて一斉に攻撃を開始する。


ソフトバンクのペッパーが面白い動きを見せたらまた追随してみる。


2015年10月17日土曜日

SolrCloud + 機械学習ランキングエンジン = R&R



【目的】
IBMがBluemix上で提供しているRetrieve and Rank(R&R)を利用し、使い方を覚えることを目的とする。
R&RとはオープンソースのApache SolrにIBMが独自に組み込んだ教師データを元にする機械学習エンジンを組み込んだ検索エンジン基盤である。
教師データを基に学習させることで検索結果のランキングをより有用性の高い順位付けにすることができる。
solrの基本はこちらを参考にしてほしい。

R&Rの名前の由来だが、通常のsolrとしての役割であるRetrieveと、機械学習を使ったRankを組み合わせたということだろう。

R&Rはまた別の見方もできるだろうか。
機械学習をさせなければ、そのままSolrとして使える。
Solrを分散化させるSolrCloudのインフラとプラットフォームを自前で用意しなくてもよいことを意味する。
IBMのクラウドをSolrのIaaS、PaaSとして使う用途にしてもいいかもしれない。



使い方を見る前に、少し脱線。
【Natural Language Classifier(NLC)との違い】
IBMのwatsonサービス群で同じようなサービスとしてNLCというものがあった。
※参考:NLCを利用したアプリ

どちらも同じ分類に対処するサービスだが、用途や学習の仕組みが違う。
(NCL)
文章のベクトル空間を作っていることで以下が実現できる。
 用途: 分類
 入力: 質問
 出力: 意図

(R&R)
質問と文章のベクトル空間を作っていることで以下が実現できる。
 用途: 検索のランク付け
 入力: 質問と回答
 出力: 関連度

NCLでFat Headな分類をした後にR&RでLong Taleな稀な種類の分類をする、という使い分けがいいだろうか。



【solrの予備知識】
R&Rの使い方を覚える前にsolrの一般的なことを確認しておく。
R&Rではclusterとcollectionまでを触れる自由度があるため、最低限ここの知識が必須となる。

R&Rのバックエンドにいるのはsolrではなく、SolrCloudである。
SolrCloudとは検索エンジンであるApache Solrのzookeeperを利用した拡張である。
勘違いがないよう補足するが、もともとSolrでも複数のノードで分散構成をとらせ、物理的、論理的に離れた位置にあるインデックス(シャード)から検索結果を得ることができる。
設定情報の一元化、スケーラビリティ、障害耐性などをzookeeperに任せることで管理の容易さをはかったものがSolrCloudである。


次に、用語の意味をまとめておく。
Solrでも一般的に使われるSolrCloudに限った話ではない。

cluster    : コレクションを管理するSolrCloudのインスタンス。

collection : 検索対象の論理的範囲を決める。
             schemaの設定ファイルはこの単位に適用される。

shard      : collectionを論理的に分割したセクション。

node       : 1つのJVMインスタンスで起動されるsolr。
           通常1サーバ内で1つだが、プロセスを分ければ複数起動可能。

core       : RDBのスキーマに相当。
             コアごとにスキーマ定義やクエリの設定を持つことが可能。


分散構成例を見たほうが理解が進むだろうか。
上位レイヤーから論理的分散させた図を書くとすると下図の関係になる。

この例では6台の物理サーバを使うことを想定する。
各論理nodeを物理境界としてのnodeとし、
若番号順3台で同じshardを持たせる(必然的にcoreも同一)。
それぞれを更新リーダとレプリカの関係にさせ、
結果2つのshard構成になっている。

cluster1
   |
collection1
   |
shard1(leader)     shard1(replica1)      shard1(replica2)
  on node1_core1     on node2_core1        on node3_core1

shard2(leader)     shard2(replica1)      shard2(replica2)
  on node4_core2     on node5_core2        on node6_core2


スケール時は次を頭に入れておくとよい。

上の図で言えば、
横軸:レプリカを増やすことで同時に処理できる検索リクエストの改善
   耐障害性の向上

縦軸:シャードを増やすことでインデクシングのパフォーマンス、データ量の増大対応
   検索における応答速度の改善

また、検索、更新ともに1つのnodeあたりのcore数は少なくした方がいい。
マルチコアさせるメリットは、ステージング環境を本番環境として入れ替えるために利用したり、または言語別にインデックスを分けて利用する場合などにあるだろう。
同一サーバ、同一アプリケーションでしか動作させられないため、可用性、バックアップ(スタンバイ)目的として増やすべきではない。

nodeを増やせば検索性能はあがるが更新性能はnodeが増えると遅くなる。
更新性能をあげるためにはshardを分けていくこととなる。

ただ、R&Rで操作できるのはcluster、collection部分だけであり、それは以下のレイヤは考慮不要である。



【操作手順】
特定の言語によらない汎用性を持たせるためcurlコマンドをシェルから実行する例を残しておく。

username、passwordはbluemixで独自に取得したものを利用すること。
url名は長いため、ベース部分を変数としておく。
# username="***"
# password="***"
# url="https://gateway.watsonplatform.net/retrieve-and-rank/api"

◆ cluster操作
(cluster情報の取得)
# curl -X GET -u "${username}":"${password}" ${url}/v1/solr_clusters | jq .


(clusterの作成)
# curl -X POST -u "${username}":"${password}" \
-H "Content-Type: application/json" \
-d "{\"cluster_size\":\"1\",\"cluster_name\":\"My cluster\"}" \
"${url}/v1/solr_clusters" | jq .

ステータスがREADYになるまで利用はできない。数分待つ必要がある。
  "solr_cluster_status": "NOT_AVAILABLE" ⇒ "READY"


(特定のclusterの詳細情報の取得)
# solr_cluster_id="***"

# curl -X GET -u "${username}":"${password}" "${url}/v1/solr_clusters/${solr_cluster_id}" | jq .

(clusterの削除)
# solr_cluster_id="***"

# curl -X DELETE -u "${username}":"${password}" ${url}/v1/solr_clusters/${solr_cluster_id}



◆ config操作
configはcollectionを作成する前に用意しておく必要がある。
collection作成時に適用するconfigを指定するためである。
※configの適用範囲はcollection単位である。

今回はサンプルにあるconfig群を活用する。
solrconfig.xml, schema.xmlなどが含まれている。

・コンフィグ サンプル(今回はこれを使う)
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/doc/retrieve-rank/resources/cranfield_solr_config.zip

自前で一から作る場合は無地のサンプルもある。
・コンフィグ プレイン(無地)サンプル
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/doc/retrieve-rank/resources/blank_example_solr_config.zip

schema.xmlではサンプルとして以下のスキーマを使う。
一般のsolrとの相違点として、機械学習の対象とするの型にはwatson_text_XXを指定する必要がある。

# head configs/schema.xml
-snip-
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="title" type="watson_text_en" indexed="true" stored="true" required="false" multiValued="true" />
<field name="author" type="watson_text_en" indexed="true" stored="true" required="false" multiValued="true" />
<field name="bibliography" type="watson_text_en" indexed="true" stored="true" required="false" multiValued="true" />
<field name="body" type="watson_text_en" indexed="true" stored="true" required="false" multiValued="true" />

<copyField source="title" dest="text"/>
<copyField source="body" dest="text"/>
<copyField source="author" dest="text"/>
<copyField source="bibliography" dest="text"/>

<copyField source="title" dest="watson_text"/>
<copyField source="body" dest="watson_text"/>
<copyField source="author" dest="watson_text"/>
<copyField source="bibliography" dest="watson_text"/>
-snip-

(config群のアップロード)
# config_name="example-config"

ファイルは圧縮しておくこと。
# file=configs/cranfield_solr_config.zip

# curl -v -i -X POST \
-H 'Content-Type: application/zip' \
-u "${username}":"${password}" \
--data-binary @${file} \
"${url}/v1/solr_clusters/${solr_cluster_id}/config/${config_name}"


(アップロードされているconfig群の取得)
# curl  -X GET -u "${username}":"${password}" \
"${url}/v1/solr_clusters/${solr_cluster_id}/config" | jq .


(config群の削除)
# curl  -X DELETE -u "${username}":"${password}" \
"${url}/v1/solr_clusters/${solr_cluster_id}/config/${config_name}" | jq .



◆ collectionの操作
(collectionの作成)
# collection_name="example-collection"

# curl -X POST -u "${username}":"${password}" \
-d "action=CREATE&name=${collection_name}&collection.configName=${config_name}" \
"${url}/v1/solr_clusters/${solr_cluster_id}/solr/admin/collections"


(collectionの取得)
# curl -s -X GET -u ${username}:${password} \
"${url}/v1/solr_clusters/${solr_cluster_id}/solr/admin/collections?action=LIST"


(collectionの削除)
# curl -s -X GET -u ${username}:${password} \
"${url}/v1/solr_clusters/${solr_cluster_id}/solr/admin/collections?action=DELETE&name=${collection}"



◆ document操作
documentとはつまり検索対象となるものである。
schema.xmlで指定した型に従ったデータをjsonで用意する。

schema.xmlの型定義にも合致しているサンプルデータを利用する。
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/doc/retrieve-rank/resources/cranfield_data.json

# head cranfield_data.json
-snip-
{
  "add" : {
    "doc" : {
      "id" : 1,
      "author" : "brenckman,m.",
      "bibliography" : "j. ae. scs. 25, 1958, 324.",
      "body" : "experimental investigation of the aerodynamics...",
      "title" : "experimental investigation of the aerodynamics of a wing in a slipstream ."
    }
  },
  "add" : {
    "doc" : {
      "id" : 2,
      "author" : "ting-yili",
      "bibliography" : "department of aeronautical engineering, rensselaer polytechnic institute troy, n.y.",
      "body" : "simple shear flow past a flat plate...",
      "title" : "simple shear flow past a flat plate in an incompressible fluid of small viscosity ."
    }
  },
-snip-

(アップロード)
# data="cranfield_data.json"
# collection="example-collection"

# curl -X POST -u "${username}":"${password}" \
-H "Content-Type: application/json" \
--data-binary @${data} \
"${url}/v1/solr_clusters/${solr_cluster_id}/solr/${collection_name}/update"


(問合わせ)
学習データを使っていない、solrだけの機能からの応答が返る。
つまりretrieve and rankのretrieve部分だけの処理結果が見える。

# qst="what is the basic mechanism of the transonic aileron buzz"
# qst_encoded=`echo $qst | nkf -wMQ | sed 's/=$//g' | tr = # | tr -d "\n"`
# wt="json"
# fl="id,title"

# curl -X GET -u "${username}":"${password}" \
"${url}/v1/solr_clusters/${solr_cluster_id}/solr/${collection_name}/select?\
q=${qst_encoded}&wt=${wt}&fl=${fl}" | jq .



◆ rankerの操作
(学習)
データ間の関連を記載した学習データを用意する。
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/doc/retrieve-rank/resources/cranfield_gt.csv

学習データは以下の形式で指定する必要がある。
"{question}","{answer_id1}","{relevance_label1}","{answer_id2}","{relevance_label2}","{...}"


# head cranfield_gt.csv
-snip-
"what similarity laws must be obeyed when constructing aeroelastic models of heated high speed aircraft.","184","3","29","3","31","3","12","2","51","2","102","2","13","1","14","1","15","1","57","3","378","3","859","3","185","2","30","2","37","2","52","1","142","1","195","1","875","3","56","2","66","2","95","2","462","1","497","2","858","2","876","2","879","2","880","2","486","0"
"what are the structural and aeroelastic problems associated with flight of high speed aircraft.","12","4","15","3","184","3","858","3","51","2","102","2","202","2","14","1","52","1","380","1","746","4","859","3","948","3","285","2","390","2","391","2","442","1","497","2","643","2","856","2","857","2","877","2","864","2","658","2","486","0"
-snip-

# train_csv="cranfield_gt.csv"
# collection="example-collection"
# ranker="example-ranker"

以下ツールでアップロードする。
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/doc/retrieve-rank/resources/train.py

学習データとtrain.pyツールは同じフォルダに置くこと(パス指定だとエラーになる)。

# python train.py -u "${username}:${password}" \
-i "${train_csv}" \
-c "${solr_cluster_id}" \
-x "${collection_name}" \
-n "${ranker}"

ここだけRESTではない理由だが、トレーニング用のcsvが一回変換かけてからPOSTされているためである。
0、1で埋まったtrainingdata.txt という名前のファイルができている。
負荷がかかる処理なのだろうか。この処理はローカルで任されている。

アップロード後に学習が完了するまで数分、時間がかかる。
個別のranker情報を参照し、statusが変わるまで待つ必要がある。
"Training" ⇒ "Available"
問い合わせてもエラーが返る。


(rankerの確認)
# curl -u "${username}":"${password}" "${url}/v1/rankers/" | jq .


(個別のranker情報の取得)
# ranker_id="***"

# curl -u "${username}":"${password}" "${url}/v1/rankers/${ranker_id}" | jq .


(問合わせ)
solr単独の機能による応答結果とどう変わったのかを見てほしい。

# qst="what is the basic mechanism of the transonic aileron buzz"
# qst_encoded=`echo $qst | nkf -wMQ | sed 's/=$//g' | tr = # | tr -d "\n"`
# wt="json"
# fl="id,title"

# curl -X GET -u "${username}":"${password}" \
"${url}/v1/solr_clusters/${solr_cluster_id}/solr/${collection_name}/fcselect?\
ranker_id=${ranker_id}&q=${qst_encoded}&wt=${wt}&fl=${fl}" | jq .


(rankerの削除)
# ranker_id="***"

# curl -X DELETE -u "${username}":"${password}" \
"${url}/v1/rankers/${ranker_id}"



参考
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/retrieve-rank.html



2015年9月2日水曜日

機械学習を使った、twitterのクレーム検知、通報システム


機械学習とその分類アルゴリズムにニューラルネットワークを利用したディープラーニングを使い、米国の携帯会社4社を対象としたクレーム検知、担当者への自動通知システムを作成した。
米国携帯会社用として作成したが、いろいろな分野でも応用が効くだろう。
※IBM Bluemix Challenge 2015"Attention Informer"という名称で応募していたアプリケーションである。


◆ UI


designed by 西大輝



◆ アプリ概要
twitterでの苦情を検知し適切な担当へ通知することを目的とする。

アプリの動きは大きく2つ。
twitterタイムラインから
● 肯定的発言、否定的発言を抽出・・・
さらに、同音異義語があっても意図するものだけを選択・・・
● クレーム内容から連絡先を自動判別・・・


簡易的に図示するとこのようになる。
twitter → positive tweets
        → negative tweets → 各担当部署
                     


①から③の部分でIBMのBluemix上にあるwatsonサービス群を利用している。
(Insights for Twitter)
①異常の検知
Negative tweetとPositive tweetを分類させる。
異常な状態は、Negative tweetの比率が対象期間全ツイートの10%を超えた場合とした。

(Natural Language Classifier(NLC))
※アプリを動作させる前に当然学習させておく必要がある。
その手段は下段"◆ コード補足"を参照のこと。

②同音異義語の判別
例えば、sprintと検索した時、それが携帯会社に関連したツイートとは限らない。
Natural Language Classifierを用いて携帯会社のtweetを自動判別させる。
  o:I wanna an Apple iPhone sold in sprint.
  x:I need to work on my sprint finish.

③通知先の判別
本アプリでは、通知先として"基地局監視部署"と"サーバ監視部署"を想定して実装した。
  基地局:Can't call any Sprint customers right now for some reason.
  サーバ:Sprint server down? There is no valid DNS server so !?

通知手段としてtwilioを利用したがメールでもなんでもよいだろう。


◆ コード
https://github.com/alpha-netzilla/attention-informer

一部、NLCの操作面について補足しておく。
APIはすべてREST経由で操作できる。
利用する言語に依らないようにcurlでのコード例を記載しておく。
※本アプリの実コードはRuby on Railsのフレームワークを使っている

○ 学習データの用意
以下の形式のcsvセットを用意する必要がある。

文章, 分類したいインテント

ここでは、ある文章が、cellphoneについて語っているのか、そうではないのかをインテント付けしている。

I'll buy new cell phone?, cellphone
Sprint network improved!!, cellphone
Do show your sprint", others
He made a sprint for escape, others
〜snip〜

以下説明のため、ここでは上記をファイル名"file=train.csv"で保存したとする。

どの程度、どういった文章を学習させればよいのかについて公式マニュアルには明確な言及がなかった。
学習後に独自に性能評価をする必要があるだろう。


○ 学習
$ url="https://gateway.watsonplatform.net/natural-language-classifier/api"

$ curl -u  ${username}:${password} \
-F training_data=@${file} \
-F training_metadata="{\"language\":\"en\",\"name\":\"claim\"}" \
"${url}/v1/classifiers"
en部分をjaにすると、日本語にも対応する。

正常に登録できれば分類器のid(classifier_id)を確認できる。
$ curl -u ${username}:${password} ${url}/v1/classifiers| jq .


○ ステータス確認
学習が終わるまでに数分かかる。
ステータスの変化で進捗を判断できる。

$ curl -u ${username}:${password} ${url}/v1/classifiers | jq .
"status": "Training" ⇒ "Available"


○ 問合わせ(POST)
適当な文章を作り、その内容がどのようにカテゴライズされるかを確認する。
学習時の言語設定をenにしている想定である。jaにしていれば日本語での質問も対応する。
$ question="I want to buy an iPhone"

$ curl -X POST -u ${username}:${password}\
-H "Content-Type:application/json" \
-d "{\"text\":\"${question}\"}" \
"${url}/v1/classifiers/${classifier_id}/classify" | jq .
{
  ~snip~
  "classes": [
    {
      "class_name": "cellphone",
      "confidence": 0.9165256889739971
    },
    {
      "class_name": "other",
      "confidence": 0.08347431102600286
    }
  ]
}

cellphoneについて言及している確率が91%になっている。


○ 分類器の削除
$ curl -X DELETE -u ${username}:${password} "${url}/${classifier_id}"



◆ NLCの選択動機
少し脱線するが、watsonサービスのNLCを本アプリを実装する上で選択した理由を書いておく。今回の対象データは自然言語という非構造化データであり、機械学習の分類系の実装であるNLCであれば対応できると判断したためである。

機械学習の基礎を確認しておこう。

● 機械学習の流れ
(教師データあり)
1.
教師データ     →     特徴ベクトル     →     予測モデル
         特徴生成               学習
            

2.
未知データ     →     特徴ベクトル     →     予測
                   予測モデル
         特徴生成               予測



● 特徴ベクトルの生成手法
(特徴抽出)
・Word2Vec NLCが利用?
・TF-IDF
・CountVectorizer

(特徴変換)
・Tokenizer
・StopWordsRemover
・n-gram
・StringIndexer
・Binarizer、Bucketizer、QuantileDiscretizer
・PCA
・PolynomialExpansion
・OneHotEncoder
・Normalizer、StandardScaler、MinMaxScaler

(特徴選択)
・VectorSlicer
・RFormula
・ChiSSelector


● 機械学習で実現可能なことと代表的な手法
(教師データあり)
・回帰(過去の実績を元に未知の数値を予測)
      - 線形回帰
      - ベイズ線形回帰

・クラス分類(与えられたデータを適切なクラスへ割り当て) NLCが得意
      - ディープラーニング(ニューラルネットワーク) NLCの実装
      - 決定木
      - SVM
      - ロジスティック回帰
       ※過去のデータを元に、ある事象が起こる確率を求められるため、回帰と名がついている。予測できる確率に対して閾値を設け、それ以上か未満かでデータの分類ができるため、クラス分類の手法として用いられている。

・レコメンデーション(価値があると思われるコンテンツを個別提示)
      - 協調フィルタリング
   ※教師データあり、なしの中間と言ったところだろうか


(教師データなし) 
・クラスタリング(類似データのグルーピング)
      - k-means
      - コング正規分布モデル

・情報圧縮/次元削減(データの本質的特徴の作成)
      - 主成分分析
      - 特異値分解


(強化学習)
・報酬を最も多く得られるように機械が適切な行動を判断(一つ一つの判断(囲碁なら指し手)の良し悪しが、勝ち負けなどの結果として後になって得られる。それぞれの指し手の正しさを教わることはできない)
      - Q学習
      - DQN


● 機械学習の予測モデルの評価
(教師データあり)
・クラス分類
      - ROC曲線(2クラス分類時)  ※補足にて若干詳しく説明
      - クロス表(多クラス分類時)

・回帰
      - 平均絶対誤差(MAE: Mean Square Error)・・・小さいほど良好
      - 二乗平均平方根誤差(RMSE: Root Mean Square Error)・・・小さいほど良好

・レコメンデーション
      - NDCG(Normalized Discounted Cumulative Gain)・・・1.0に近いほど良好
      - 平均絶対誤差(MAE: Mean Square Error)・・・小さいほど良好
      - 二乗平均平方根誤差(RMSE: Root Mean Square Error)・・・小さいほど良好


(教師データなし)
      明確な回答がないため、満足度、売上、利益、になるだろうか。


-------------------

〜補足〜
2クラス(2項、2値)分類の評価時に必須となる基礎的な知識を下の図を元に覚書として記録しておく。





・精度(Precision)
Precision = A / (A+B)
○と推測したデータのうち、正解が○のデータである割合。
100%に近いほど良好。

・真陽性率(TPR: True Positive Rate) ※再現率(Recall)とも呼ばれる
TPR = A / (A + C)
正解が○のデータのうち、正しく○と推測した割合。
100%に近いほど良好。

・正解率(Accuracy)
Accuracy = (A+D) / (A + B + C + D)
全データのうち正解○のデータを正しく○、正解×のデータを正しく×と推測した割合。
100%に近いほど良好。

・偽陽性率(FPR: False Positive Rate)
FPR = B / (B + D)
正解が×のデータのうち、誤って○と推測した割合。
0%に近いほど良好。

・ROC(Receiver Operating Characteristic)曲線
横軸に偽陽性率(FPR)、縦軸に真陽性率(TPR)をとり閾値を変化させた場合の曲線である。真陽性率(TPR)と偽陽性率(FPR)は一方が良くなれば他方が悪くなるトレードオフの関係にあった。

閾値が1.0なら、どのようなデータも×と判定するため(AとBがゼロ)、真陽性率も偽陽性率も共に0%となる。
閾値が0.0なら、どのようなデータも○と判定するため(CとDがゼロ)、真陽性率も偽陽性率も共に100%となる

閾値を1.0から0.0へ変化させていく際に、偽陽性率をあまり悪化させず(横軸が小さい時に)、信用性率が向上する(縦軸が大きくなる)左上に張り付くようなグラフほど、良好であると判断できる。定量化した指標としてAUC(Area Under the Curve)がある。

・F値(F Score)
トレードオフの関係にある指標を統合的に見る指標。
1.0に近いほど良好。


(練習問題)
イヌの画像が50枚、イヌ以外の画像が50枚の計100枚の画像がある。

1. 精度
分類機は60枚をイヌと認識し、48枚が正解であった。
48 / 60 * 100 = 80%

2. 真陽性率(再現率)
50枚のイヌの画像のうち分類機が48枚をイヌの画像と正しく認識した。
48 / 50 * 100 = 96%

3. 正解率
100枚のうち、86枚を正確に認識(イヌをイヌと、イヌ以外をイヌ以外)した。
86 / 100 * 100 = 86%