まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:cognitive

IBM ワトソンなどの各種コグニティブエンジンを使う際に、重要なのは学習データだと思っています。

要はコグニティブエンジンを使って問い合わせを行うわけですが、その問い合わせする前に何らかの学習をする必要があり、そこで何をどれだけ学習させたかによって問い合わせの精度が変わってくるからです。

で、先日こんなツイートをしました:
2017022601

https://twitter.com/dotnsf/status/834959690803007488


↑は、その学習データを何らかの方法で集める際に、(非同期処理で集めるのではなく)マルチスレッド処理がいいのではないか、と思ってつぶやいたのでした。このことをもう少し詳しく紹介しようと思います。なお、あくまで特定条件下での個人見解なので他の人の意見も聞いてみたいと思ってます。

やろうと思っているのは、大まかにはこんな内容です:
  1. あらかじめ用意したインターネット上の URL のリストから、その HTML を取得して学習データにしたい
  2. この「リスト」が大量にあるケースを想定する
  3. なお、リストの中には実在しない URL が存在している可能性がある(つまりリストそのものが間違っている可能性がある)
  4. また URL は実在しているのだが、ネットワーク障害や DNS の設定ミスなど何らかの原因でアクセスする際に非常に長い時間がかかる(長い時間がかかった結果、タイムアウトになったり成功したりする)場合もある

1と2はごく普通の条件ですよね。ここではインターネット上の URL のリストは配列変数で用意されているものとしましょう。配列から1つずつ URL を取り出して、その URL の HTML を取得する、という処理を施すことになります。

問題は3と4の条件です(でも現実的に想定すべき条件だと思ってます)。3は用意されたリストそのものが間違っているというケース、つまり与えられた URL は "Unknown Host" になったり、404 などのエラーが返ってくることを想定しないといけない、ということです。

また4は更にややこしい条件です。成功するかしないかではなく、こちらからは手が出せない箇所のなんらかの障害によって目的の URL へのアクセスに非常に時間がかかってしまうケースです。時間がかかった結果、目的の HTML が取得できればいいのですが、最終的にタイムアウトエラーが発生することもあり得る、というケースを想定する必要があります。


要するにこれらを想定したエラー対策が必要になるのですが、まずは3と4を無視して(エラーが発生しない前提で)普通にアルゴリズムを考えるとこんな感じになるでしょうか:
//. URL の配列
urls = [
  "http://xxx.com/a1.html",
  "https://xxx.com/a2.html",
  "https://yyy.net/",
  "http://abc.com/xyz.html",
     :
     :
];

//. URL を1つずつ取り出して HTML を取り出す
forall( url in urls ){
  html = getHTML( url );
      :
      :
  (取り出した HTML を使って学習処理を行う)
      :
      :
}


↑の例ですと、getHTML 関数の中で実際に指定した URL にアクセスして HTML を取り出す、という処理をするものとします。そしてこの関数の中で3や4を原因とするエラーや時間がかかるといった現象が発生することを想定してみます。

3のケースは実は単純で、実在しない URL が指定された場合はこの関数の返り値を null などにして、null でなかった場合のみ処理を続ける、という判断を加えることで解決します:
//. URL の配列
urls = [
  "http://xxx.com/a1.html",
  "https://xxx.com/a2.html",
  "https://yyy.net/",
  "http://abc.com/xyz.html",
     :
     :
];

//. URL を1つずつ取り出して HTML を取り出す
forall( url in urls ){
  html = getHTML( url );
  if( html != null ){ //. 3の対策
      :
      :
  (取り出した HTML を使って学習処理を行う)
      :
      :
  }
}


さて問題は 4 のケースです。3 のアルゴリズムを単純に(シーケンシャルに)実行した場合、特定の URL から HTML を取り出す処理に時間がかかってしまうような事態が発生すると、リストの途中で処理が先に進まなくなってしまう、ということになります。このようなケースを想定した上で効率よく処理を実行するにはどう改良すべきでしょうか?

1つの方法として考えたのが非同期処理です。上記のループ部分を非同期に処理して、リスト内の各 URL へのアクセスを非同期に行う、という方法です。アルゴリズムにするとこのような感じになるでしょうか:
//. URL の配列
urls = [
  "http://xxx.com/a1.html",
  "https://xxx.com/a2.html",
  "https://yyy.net/",
  "http://abc.com/xyz.html",
     :
     :
];

//. URL を1つずつ取り出して HTML を取り出す
forall( url in urls ){
  html = getHTML( url, function( err, html ){  //. getHTML を非同期に実行する
    if( err ){
      //. 3. のエラー処理
    }else{
//. 成功した場合
: : (取り出した HTML を使って学習処理を行う) : : } }); }
↑非同期ということで JavaScript っぽくしてみました

このように非同期に処理を行うことで、「各 URL の HTML を取得する」という命令を全て先に実行しておき、(成功にせよエラーにせよ)取得の処理が終わったらそれぞれの続きを行う、というロジックです。こうすることで 4 のような事態が発生しても、正常な URL に対する処理は邪魔されることなく先に終了し、時間のかかる処理だけが後から実行される、という一見きれいな形になります。

しかし、この方法にも問題点がありました。それは URL のリストが膨大だった場合です。上記のコードが非同期に実行されるとまず全て URL に対する HTML 取得のリクエストが発行されます。そしてその処理はシステムのメモリ量や TCP ソケット数上限を超えて実行されてしまう可能性があります。この部分はコーディングというよりもシステムのメモリ管理やソケット数管理などの厄介そうな処理を行う必要がでてきてしまいます。

で、冒頭のマルチスレッドです。上記の非同期で行っていた部分をマルチスレッドに書き換えることで、(スレッド生成間のスリープ時間を調整するなどの)ある程度のスケジュール調整をした上で同時に HTML を取得する処理を行うことができるようになります。例えばこんな感じです(ここは言語依存がありそうなので、Java 丸出しで記述しています):
//. URL の配列
urls = [
  "http://xxx.com/a1.html",
  "https://xxx.com/a2.html",
  "https://yyy.net/",
  "http://abc.com/xyz.html",
     :
     :
];

//. URL を1つずつ取り出して HTML を取り出す
forall( url in urls ){
  //. 子スレッドを生成して、スレッドの中で取得処理を実行
  Download dl = new Download( url );
  Thread t = new Thread( t );
  t.start();

  try{
    Thread.sleep( 1000 ); //. 1秒待ってから次の URL を処理
  }catch( Exception e ){
  }
}


//. マルチスレッドで動くインスタンス
public class Download implements Runnable{
  private String url = "";
  public Download( String url ){
    this.url = url;
  }

  public void run(){
    html = getHTML( url );
    if( html != null ){
      :
      :
  (取り出した HTML を使って学習処理を行う)
      :
      :
    }
  }
}

↑マルチスレッドなので Java 全開の記述法で

この方法であれば、各 URL に対する HTML の取得は別々のスレッドで行われるため、特定の URL で 4 のような遅延現象が発生しても、他の URL に対する処理がその遅延に巻き込まれることはありません。また、この例では1秒(1000ミリ秒)おきにスレッドを生成するようにしています。例えば1スレッドの処理が2秒程度かかるようなケースであっても、3つ目のスレッドが生成されたタイミングで最初のスレッドの処理は終了している可能性が高くなり、同時に実行されるスレッドの数がさほどは増えないようなアルゴリズムになっています。仮に 4 のようなケースが発生したとしても、そのスレッドだけはしばらくの間生き続けることになりますが、他のスレッドは生成しては処理されて消えてゆくという流れになるので、やはりシステムの限界を意識するような処理にはなりにくいアルゴリズムになっているのでした。


という所まで作っての「マルチスレッド処理が効率よい」という冒頭の結論に至ったわけでした。要するにこれなら深く考えずに作って動かしてもややこしい対応が必要になる心配が少ないかな、と。またマルチスレッド処理となると Java が得意とする処理ロジックであり、オッサン脳の出番が増えるかもしれないなあ、と感じたのでした。

ゆるキャラを画像で検索するサービスを作って公開してみました:
http://yuru.mybluemix.net/

まず最初に、自分はある程度ゆるキャラに詳しいと思っています。積極的な興味というよりは、マンホールに詳しくなっていると、最近はそのマンホールのデザインにゆるキャラが使われることが珍しくなくなってきたので、自然と(?)ゆるキャラにも詳しくなってしまうのでした。。
2017011500
 

さて、ゆるキャラに限らないのですが、イマドキ何かを調べようとした時にはまず『ググる』のが定番です。ただ、それは調べるためのキーワードが分かっている場合です。ゆるキャラの場合、名前が分かっていれば名前でググれば確実ですし、名前が分からなくても出身地とかが分かれば「ゆるキャラ 東京都」などで検索すればいくつか候補が見つかるのでそこから調べる方法もあります。

しかし問題は名前も出身地も分からず、検索するためのキーワードがない場合です。例えば目の前に着ぐるみそのゆるキャラ本体がいて、写真は撮れるんだけど、そのゆるキャラがなんという名前で、どこのゆるキャラで、どんな特徴を持っているのか、、、といった情報を調べる具体的な方法がなかったように感じていました。

といった背景もあり、「画像からゆるキャラを調べる」ことができるようなウェブサービスを作ってみた、という経緯です。いわゆる「類似画像検索」を行うため、コグニティブエンジンである IBM WatsonVisual Recognition API を使って実装してみました:
http://yuru.mybluemix.net/


使い方はシンプルで、ウェブサイトをPCかスマホのブラウザで開き、ファイル選択ボタンを押して、ローカルシステムやフォトライブラリ等から目的の画像を選択するだけです:
2017011501


PC の場合に限り、目的の画像ファイルを画面上部のこの辺りにドラッグ&ドロップしても構いません:
2017011502


例えばこの画像のゆるキャラを調べてみることにしました。まあ有名なヒトなので答はわかっているのですが、ちょっとトリッキーなアイテムも写っていて普段と違う画像になっているので、いいサンプルかな、と:
く


この画像を選択するか、画面内にドラッグ&ドロップすると画面が暗転して検索が始まります:
2017011503


暗転から戻ると、検索結果として候補キャラが画面下部に表示されているはずです。最大で100件表示されます:
2017011504


今回の画像の場合、下の方にそれっぽいのが見つかりました:
2017011505


該当する結果の画像をクリックすると、そのゆるキャラの情報がポップアップします。ご存知「くまモン」でした。なお PC であればマウスオーバーでも表示されます:
2017011506


まだまだ学習量が充分ではなく、第一候補となることはまだ珍しいとか、(着ぐるみの写真ではなく)絵の場合には精度が落ちるとか、横から写した画像に弱いとか、背景画像に左右されることが多いとか、まだまだ問題はありますが、一応動くものが作れたと思ってます。

実際の用途としてはある程度いけるかな、と思ってます。もちろん精度高く検索できることが理想ですが、上記で書いたように「名前が分かれば色々調べる方法はあるんだけど、肝心の名前が出てこない」のを解決するツールとして考えると、検索結果の候補の中に含まれていれば、それはそれでオッケーかな、と。


なお、今回のサービスは Visual Recognition の中では現時点でベータ版の /v3/collections/ で始まる API を使って開発しています。今後の仕様変更などがあった場合にサービスがどうなるか何とも言えませんが、なるべく対応させていく予定です。合わせてもう少し学習データの量を増やして検索精度を上げられないか、がんばってみます。


IBM Bluemix から提供されている認識型人工知能 API の1つ "Speech to Text" が2015年7月1日のアップデートで日本語に対応しました!
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/speech-to-text.html

音声ファイル(.wav など)をインプットとして与えると、その内容のテキストと、その変換の確度をテキストでアウトプットしてくれる、というサービスです。オンラインのデモサイトが用意されているので、まずはどのような内容なのかをデモで確認してみましょう:
https://speech-to-text-demo.mybluemix.net/

2015072001


まず "Transcribe Audio" と書かれている所を参照し、今回のデモで行う作業を IBM Watson の学習にご協力いただけるかどうかを設定します。学習にご協力いただける場合は "Allow Watson to learn from this session" を、この作業を学習してほしくない場合は "Opt Out" を選択してください。更にその下で今回の作業で使う音声の言語情報を設定します。今回は日本語音声でテストしたいので "Japanese broadband model (16KHz)" を選択しておきます。加えて実際の音声が聞こえるように PC のスピーカーを有効にしておきます。これだけで事前準備は完了です:
2015072002


では実際にサンプル音声データを使って認識させてみます。"Play Sample 1" ボタンをクリックします:
2015072003


サンプルの日本語音声が流れ始めます。同時にその音声の認識結果が表示されはじめます。
2015072006


最後まで再生が終わると、最終認識結果が表示されます。実際に試していただくとわかるのですが、Sample 1 は正しい結果に認識できていることがわかります。しかもちゃんと漢字になっていますね。。:
 2015072004


これが Watson Speech to Text API を使ったアプリの例です。このアプリで実現している内容と同様に、音声データをインプットとしてポストすると、認識結果がテキストで得られる、という API が用意されています。この API を自分のアプリケーションの中で利用することができる、というものです。

では実際にこの API をアプリケーションに組み込んで使ってみる、という具体例を紹介します。まずは Bluemix にログインし、実際のアプリケーションサーバーとなるランタイムを作成します。Speech to Text API は REST API なのでプログラミング言語に依存していませんが、今回は Java のサンプルを紹介するので Liberty for Java のランタイムを作成します:
2015072007


アプリ名は適当に(この例では kkimura-java-s2t と)付けておきます:
2015072008


ランタイムが作成できたら「概要」メニューから「サービスまたは API の追加」をクリックします:
2015072009


サービスの一覧が表示されます。今回の目的である Watson カテゴリ内の "Speech To Text" を選択します:
2015072010


"Speech To Text" サービスの説明が表示されます。日本語に対応していることが確認できます。この画面で「作成」ボタンを押して、このサービスが先程作成したランタイムに紐付けた形で利用できるようにします:
2015072011


ちなみに、この画面の下部にはサービスの価格に関する情報も表示されているので念のため確認ください。この API は音声データの長さで課金されます。最初の 1000 分が無料、それ以降は1分につき 2.10 円です。なお無料トライアル期間中のユーザーは課金対象ではありません:
2015072012


ランタイムに Speech to Text サービスが紐付けられると、ランタイムの環境変数からこのサービスを利用するための情報を参照できるようになります:
2015072013


この環境情報はこのような内容になっているはずです。"url" に API のエンドポイント(のベースとなる)値、そして "username" と "password" にはこの API を利用する際に必要になる認証情報が記載されています。これらの値を後で使います:
{
  "speech_to_text": [
    {
      "name": "Speech To Text-fc",
      "label": "speech_to_text",
      "plan": "standard",
      "credentials": {
        "url": "https://stream.watsonplatform.net/speech-to-text/api",
        "username": "(username)",
        "password": "(password)"
      }
    }
  ]
}

そして、実際に API にポストする日本語音声ファイルを用意します。今回はこちらのサイトから「あいうえお1(wav)」と書かれた .wav ファイル(aiueo1.wav)をダウンロードして使わせていただくことにします。もちろん他の音声ファイルでも構いません。現時点での対応フォーマットは flac/l16/wav です:
日本語音声サンプル


で、こんな感じのアプリケーションを作ってみました。まずはシンプルに音声ファイルを指定してアップロードする HTML ページのファイルです。アップロードするファイルは "audio_file" という名前で、./speech2text にポストします:
<html>
<head>
<title>Speech to Text</title>
</head>

<body>

<form name="frm" method="post" enctype="multipart/form-data" action="./speech2text">
<input type="file" name="audio_file"/><input type="submit" value="Submit"/>
</form>

</body>

</html>



そして、このページからアップロードされた音声ファイルを使って Speech To Text API を実行して、その結果を返すサーブレット(./speech2text)を以下の内容で作成します。なおこのサーブレットは Jakarta Commons HTTPClient 3.1JSON Simple 1.1.1 を使っています。必要であればこれらのモジュールも入手してください:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

public class SpeechToTextServlet extends HttpServlet {
  @Override
  protected void doPost( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException{
    String contenttype = "application/json; charset=UTF-8";
    String audio_type = "audio/wav";
    byte[] audio_file = null;
    String out = "";

    // Speech to Text を使うための username と password(環境変数にかかれていたもの)
String username = "(username)", password = "(password)"; req.setCharacterEncoding( "UTF-8" ); ServletFileUpload upload = new ServletFileUpload(); upload.setHeaderEncoding( "UTF-8" ); JSONParser parser = new JSONParser(); try{ FileItemIterator iterator = upload.getItemIterator( req ); while( iterator.hasNext() ){ FileItemStream item = iterator.next(); InputStream stream = item.openStream(); if( !item.isFormField() ){ String fieldname = item.getFieldName();
// audio_file フィールドに指定された音声ファイルのバイナリを取得する if( fieldname.equals( "audio_file" ) ){ audio_type = item.getContentType(); // 音声ファイルの Content-Type int len, size = 0; byte[] buffer = new byte[10*1024*1024]; //. 10MB MAX ByteArrayOutputStream baos = new ByteArrayOutputStream(); while( ( len = stream.read( buffer, 0, buffer.length ) ) != -1 ){ baos.write( buffer, 0, len ); size += len; } audio_file = baos.toByteArray(); // 音声ファイルのバイト配列 } } } if( audio_file != null ){ HttpClient client = new HttpClient(); byte[] b64data = Base64.encodeBase64( ( username + ":" + password ).getBytes() );
// /v1/recognize に音声ファイルのバイナリをポストする(パラメータで日本語音声であることを指定) PostMethod post = new PostMethod( "https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?model=ja-JP_BroadbandModel" ); post.setRequestHeader( "Authorization", "Basic " + new String( b64data ) ); post.setRequestHeader( "Content-Type", audio_type ); ByteArrayRequestEntity entity = new ByteArrayRequestEntity( audio_file ); post.setRequestEntity( entity ); int sc = client.executeMethod( post ); if( sc == 200 ){
// ポスト結果(JSON)を UTF-8 テキストで取り出す byte[] b = post.getResponseBody(); out = new String( b, "UTF-8" ); // ※
// テキスト内の日本語認識結果と、その確度(自信)を取り出す JSONObject obj = ( JSONObject )parser.parse( out ); JSONArray results = ( JSONArray )obj.get( "results" ); if( results.size() > 0 ){ JSONObject result = ( JSONObject )results.get( 0 ); JSONArray alternatives = ( JSONArray )result.get( "alternatives" ); for( int i = 0; i < alternatives.size(); i ++ ){ JSONObject alternative = ( JSONObject )alternatives.get( i ); Double confidence = ( Double )alternative.get( "confidence" ); String transcript = ( String )alternative.get( "transcript" ); out = transcript + "\t" + confidence; // 結果をタブでつないで出力する //System.out.println( out ); } } } } }catch( Exception e ){ e.printStackTrace(); } res.setContentType( contenttype ); res.setCharacterEncoding( "UTF-8" ); res.getWriter().println( out ); } }

肝になっているのは赤字で記載した部分です。Speech to Text には何種類かの API がありますが、今回はシンプルに実行する /v1/recognize を使った例を紹介しています。この API はまず model パラメータで言語情報を指定します。今回は日本語音声ファイルを試したいので、model=ja-JP_BroadbandModel と決め打ちで指定しています。これ以外にも認識の途中経過を結果テキストに含めるような指定をすることもできますが、今回は認識した最終結果だけをその確度と一緒に返す仕様(デフォルト)で実行しています。

そして環境変数で確認した username と password を使った Basic 認証、および認識させる音声ファイルの Content-Type を HTTP ヘッダに追加し、音声ファイルのバイナリを本体としてする、という内容になっています。上記例は Java でその内容を実装していますが、同様の処理を記述すれば他の言語でも同じ処理を実行できるはずです。

この処理が成功すると、HTTP のレスポンス(上記コードの※の out の内容)として以下の様な JSON テキストが返されるはずです:
{
  "results": [
    {
      "alternatives": [
        {
          "confidence": 0.5490435361862183, 
          "transcript": "ああ いう よう "
        }
      ], 
      "final": true
    }
  ], 
  "result_index": 0
}

上記の中身の "transcript" が認識結果のテキスト(「あいうえお」のはずが「ああ いう よう」と聞こえちゃったんですね。。)、その確度が "confidence" に付与されています。 なので、この JSON フォーマットから目的の値だけを取り出して、上記例では "transcript" と "confidence" の値をタブ("\t")でつないで返す、という内容のサーブレットにしました。

したがって、このプログラムを実際に動かして、用意した aiueo1.wav をアップロードすると、このような結果がブラウザ画面に表示されることになります:
2015072001


Watson Speech to Text API の特徴の1つとして、「一般的な会話がなされている前提で、会話として確率の高そうな結果が優先される」ように感じています。上記例だと、一般的な会話の中には「あいうえお」という発音だけがなされる可能性は低いのも事実だと思っています。一方で「ああ、言うよ~」はより会話っぽいので、こういう結果の方がどちらかというと(会話として)可能性が高い、と判断するようです。良くも悪くも会話優先で変換してくれるような印象を持っています。


と、これが Watson の Speech to Text API の具体的な利用例です。パラメータで挙動をある程度コントロールすることもできますし、結果により詳しい情報を含めることもできます。音声というメディアをアプリケーションに組み組むのに便利な API だと思うので、様々なアプリアイデアの中で使ってみてください。


なお、Speech to Text API のリファレンスはこちらを参照ください:
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/apis/#!/speech-to-text/


やられた・・・ orz

Microsoft が作って話題になった写真からの性別&年齢推定サービス How-Old.net
2015050501

精度に???な所はあるけど面白い、とネットでも結構話題になった印象です。

そして悔しい。自分達にも同じようなサービスがあるのに、正しく情報を伝えきれなかったせいで話題を Microsoft に持っていかれてしまいました。残念だ。 改めて Microsoft のマーケティングのうまさと画像認識機能への本気度を感じました。


いい機会なので、自分達が提供している機能と Microsoft の機能との違いを明確にしながら、この how-old.net に相当する機能を自分で作るにはどうしたらいいか、という話をしようと思います。

この画像認識/顔認識の機能は比較的最近になってホットになりつつある技術分野です。最近になってなぜ?かというと、この所ニューラルネットやディープラーニング技術による人工知能分野が活気づいてきており、特にこの「画像認識」や「パターン認識」の分野に関してはディープラーニングによってある程度の成果を上げることができつつあることが挙げられます。画像認識コンテストではディープラーニング技術を使ったエンジンが軒並み上位の結果を残している、という事実もあります。つまり画像認識はここ数年で研究レベルから実用レベルになりつつあると言えます。

IBM も人工知能研究には長い歴史があります。最近は Watson というブランドの下で色々な人工知能エンジンの実用化に向けた取り組みを行っていました。その一部は誰でも使えるように IBM Bluemix を通じて API としても提供されるようになりました。ただ実は Watson はディープラーニング技術をメインにしているわけではありません。Watson にもパターン認識機能がありますし、その API も公開されていますが、現時点で人気のディープラーニングをベースとしたものではありませんでした。

そのような中で IBM は2015年3月にディープラーニング技術に優れた AlchemyAPI 社を買収しました。画像認識だけでなく数々の人工知能エンジンにディープラーニング技術を取り入れている同社の技術を取り込んだことで、IBM の人工知能エンジンはディープラーニングをベースとした Alchemy と、大量の仮説から絞り込んでゆく Watson という、2つの柱ができました。このディープラーニングだけではない人工知能エンジンを研究している点が IBM の強みといえるかもしれません。

現在は Watson だけでなく、Alchemy の API も IBM Bluemix を通じて、ある程度の無料利用枠を設けて提供されています。これが何を意味するかというと、プログラマーやデベロッパーと呼ばれるプログラミングのできる人であれば誰でも画像認識やその他の人工知能 API を使って how-old.net のようなサービスを作ることができる、ということになります。

この「誰かが作ったものを使う」だけではなく「自分で作ることもできるような機能も提供されている」のが特徴です。例えば Alchemy にも画像から顔を認識する機能がウェブ API として提供されています。以前に自分のブログで紹介したことがあるので、興味のある方はこちらを参照ください:
AlchemyAPI の顔認識 API を使ってみる


また IBM が提供する人工知能 API の特徴として、認識結果の自信度合いも結果に含まれる、という点が挙げられます。例えば「この顔は男性だと思うけど、その確率は99%」とか「この人の年齢は30歳前後だと思うけど、その確率は60%」といった具合です。ピンポイントで回答しているわけではなく、現在の人工知能エンジンが弾きだした結果をその確実性と一緒に取得できるような API が提供されている点が特徴です。例えばですが API を実行した結果の自信が60%以下だった場合は使わない、といった判断をプログラミング内で行うことで精度の高い結果だけをサービスとして採用する、という条件分岐を含めることもできます。

また、特に顔認識機能に関しては有名人の顔に限りますが面白い特徴があり、性別や年齢だけでなく「○○さんの顔」として識別できるという特徴があります。例えばアメリカでも有名な渡辺謙さんの画像を問い合わせてみるとこんな結果になります。"Ken Watanabe" と認識されているのがわかるでしょうか?:
2015050502


まだ試作段階なので今後変更の予定もありますが、一応上記の確認ができるようなサービスを作ってこちらで公開してみました。興味ある方は使ってみてください:
http://dotnsf-watson.mybluemix.net/


同じ顔認識機能でも、こういった特徴というか特色が各社ごとにあるのも面白いですよね。IBM の AlchemyAPI ではこのような「有名人であればピンポイントで識別する」機能が提供されている点が面白いです。 興味のあるプログラマの皆さんは、上記の AlchemyAPI の顔認識 API を使ってみる を参考に画像をポストして、認識結果を JSON で受け取って表示する、というアプリを作ってみることに挑戦してみてください。いずれ近い将来にこのブログでもその内容を紹介するつもりです。
 





 

このエントリの続きです。ここで紹介した機能を実現する API の使い方を紹介します:


この機能は IBM Bluemix を通じて提供されているコグニティブサービスの1つである Watson Message Resonance サービスから使うことができます。そのため、まずは Bluemix にログインして、なんらかのランタイムにバインドする形で同サービスを追加する必要があります。ちなみにこのサービスは2015年4月19日時点ではベータ版であり、IBM Bluemix 利用者であれば無料で利用することができます:
2015041901


ランタイムに Message Resonance サービスを追加後に「資格情報」を参照して、このサービスを利用する際のユーザーID(username)とパスワード(password)情報を確認しておきます:
2015041902


ここまでの事前準備ができていれば、Watson Message Resonance サービスの API を使うことができます。以下は Java を使った場合のサンプルですが、REST API なので Java 以外の言語であっても同様に利用することができます:
try{
  String username = "(上記 username の値)";
  String password = "(上記 password の値)";
  String word = "Bluemix"; // 流行性を調べたい単語

  byte[] b64data = Base64.encodeBase64( username + ":" + password.getBytes() );

  //. dataset 対象業界で、1はクラウドコンピューティング、2 はビッグデータ
  GetMethod get = new GetMethod(
    "https://gateway.watsonplatform.net/message-resonance-beta/api/v1/ringscore?dataset=1&text=" + word );
  get.setRequestHeader( "Authorization", "Basic " + new String( b64data ) );
  int sc = client.executeMethod( get );
  String json = get.getResponseBodyAsString(); //. 結果の JSON 文字列
  :
  :
}catch( Exception e ){
 e.printStackTrace();
}

上記のように、https://gateway.watsonplatform.net/message-resonance-beta/api/v1/ringscore に対して Get メソッドを実行します。その際の text パラメータに流行性を調べたい単語を指定します。また dataset パラメータは流行性を調べる対象業界で、1はクラウド、2はビッグデータです。シンプルなので Java 以外への応用もさほど難しくないと思っています。

このコードを実行した結果(上記コードの場合は json 変数の値)は以下の様な JSON 文字列になります:
{"dataset":1,"word":"Bluemix","overall":19,"prevalence":10,"volume":4,"duration":5}

この中身を少し解説します。
"dataset":1 は URL で指定した dataset=1 が結果にも含まれて返ってきているだけです。"word":"Bluemix" も同様です。なので実際の実行結果といえるのはこの続き部分になります。

"overall":19 は流行度合いの総合的な結果であり、以下の3つの結果の合計値になっています。
"prevalence":10 は、その単語の今現在の流行度合いを示しています。この場合ではその値が 10 ということになります。
"volume":4 はその単語がこれまでにどの程度の量/回数で使われているか、という指標です。多く使われていれば今流行している、といえるわけではありませんが、過去も含めてどれだけ多く使われていたか、という指標になる数字です。この場合ではその値は 4 という評価です。
最後の "duration":5 はどの程度の期間使われているか、という指標になります。当然長い期間使われ続けている単語であればずっと流行しているともいえますが、短い期間で爆発的に流行したものかどうかを調べることもできます。この単語の場合はその値が 5 という評価です。

つまりこの "Bluemix" という単語の場合は現在の流行度 10、データ量 5、流行期間 4 で、総合結果は19という結果になった、という意味です。 

この API は単語ごとにしか問い合わせができませんが、複数の語について調べるには文章を単語に分解して、その結果の各単語ごとにこの API を実行すればよいことになります。なお、残念ながらこの API は 2015 年4月19日現在ではまだ英語の単語に対してのみ利用可能です。


なお、Message Resonance API のリファレンスはこちらを参照ください:
Message Resonance Reference

このページのトップヘ