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

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

この記事の続きです:
Watson API Explorer の使いかた

上記記事で Watson API Explorer サービスの紹介をしました。今回はより実践的に Watson API を使ってみます。

今回対象にする Watson API は上記記事でも紹介した Natural Language Classifier (以下 NLC)とします。前回は学習前の(空の)データを確認しただけですが、今回は実際にデータを学習させた上で、学習データに対して問い合わせをする、という一連の機能を Watson API Explorer で確認する、という手順を行います。

この手順を紹介する上で、あらかじめ NLC サービスインスタンスを Bluemix 上に作成し、認証情報(username と password)を取得しておく必要があります。その手順については上記前回の記事を参照してください。

加えて今回はデータを学習させる手順が含まれるので、サンプルの学習用データを用意しました。以下のリンクをクリックして、nlc_api_training.zip をダウンロード&展開してください:
http://dotnsf.blog.jp/nlc_api_training.zip

展開すると2つのファイルが出来上がります。いずれもテキストファイル(JSON ファイルと CSV ファイル)なので、興味のある人はテキストエディタで中身を確認してみてください:
2016063001


では実際に Watson API Explorer で NLC を使ってみます。まずは NLC API のページに移動します:
https://watson-api-explorer.mybluemix.net/apis/natural-language-classifier-v1

そして取得済みの username と password を画面右上欄に入力します。これで準備完了:
2016063002


最初にデータを学習させてみますが、その前にまだ何も学習されていないことを確認しておきましょう。現在の状態を確認する API はリストの一番上にある GET /v1/classifiers です。ここをクリックして展開します:
2016063003


この API の説明やパラメータ、実行結果の意味などが表示されますが、この API はパラメータなしで実行するので、特に何も指定する項目はありません。そのまま "Try it out!" ボタンをクリックして実行します。するとこの API が実行され、その結果(Response Body)を見ると "classifiers" が空配列([])になっており、まだ何も学習されていないことがわかります:
2016063004


なお、この上記画面内の "Request URL" を見ると、同じ処理を curl で実行する場合のコマンド内容を確認できます。また "Response Headers" には REST API 実行結果に含まれている HTTP ヘッダの内容を確認することもできます。

もしもこのコマンドの実行結果が空配列ではなく何か含まれていて、次の学習コマンドを実行する前に内容をリセットする場合は、API リストの下から2番目にある DELETE /v1/classifiers/{classifier_id} を実行して現在の学習内容を削除できます。その方法は最後に紹介しますが、ここでは現在は何も学習していない状態であるとして以下を紹介します。

では NLC に学習データを送信してみましょう。新しいデータを学習させる場合の API は上から2番目の POST /v1/classifiers を使います:
2016063005


パラメータの説明を見ると、この API の実行には2つの情報を(POST データとして)与える必要があると書かれています。1つは training_meta_data という名前の JSON データで、もう1つは training_data という名前の CSV データです。実はこれらのサンプルが上記でサンプル zip ファイルを展開した中に含まれていた2つのファイルです。

training_meta_data のサンプルが demo_metadata.json です。サンプルファイルの中身は以下のようになっているはずです:
{"language":"ja","name":"dotnsf_nlc_demo"}

非常にシンプルな内容の JSON テキストです。"language" はこの後の学習データに使われている言語(日本語なので "ja" を指定)、また "name" はこの学習データに付ける名前(この例では "dotnsf_nlc_demo")です。"name" の内容は適当に変更しても構いません。

もう1つの training_data のサンプルが dwj.csv です。 これが学習データに相当するもので、こちらもテキストエディタで開くとわかりますが、以下の様な内容の CSV ファイルです:
Bluemix の Auto-Scaling サービスは、ターゲット環境の・・・,cloud
この記事では、IBM DevOps Services で使用されるスプリント・・・,cloud
  :
  :
Java 8 には、より簡単にプログラムを作成できるように・・・,java
  :
  :
ほとんどの Linux システムでは、仮想マシン (VM) を作成およびサポートするための・・・,linux
  :
  :

CSV の1行は2つだけの列で構成されており、1つ目が本文、2つ目は本文のカテゴリーになっています。つまり「(カテゴリー)の例として(本文)がある」ということを学習データとして与えています。これを1つのカテゴリーについて充分な(この dwj.csv では1つのカテゴリーにつき約100個の)本文を与えて、それを元に学習させている、ということです。

もう少し細かく説明すると、与えた本文は(training_meta_data で指定した「日本語」のルールで)単語に区切られ、品詞に分類した上でその出現頻度や傾向などから「カテゴリ(例えば cloud)とは、こういう特徴を持ったものだ」ということを自分で判断・理解して学習させています。このような例をカテゴリごとに大量に用意して、(上記サンプルでは)cloud とはこういうもの、java とはこういうもの、linux とはこういうもの、・・・といった内容を学習させる、そのための学習元データになっています。

したがって、上記の dwj.csv ファイルはそのままでも動くサンプルですが、新しい情報を書き加えたり、新しいカテゴリのデータを加えて与えたりしても動きます(更新後の内容を学習します)。興味があれば自分なりにカスタマイズしてみてください。


改めて、この2つのサンプルファイルを使って NLC の学習 API を実行してみます。Watson API Explorer のリスト上から2番目の POST /v1/classifiers を展開し、training_meta_data に demo_metadata.json を、training_data に dwj.csv を指定して、"Try it out!" をクリックします:
2016070101


すると指定した2つのファイルがアップロードされ、学習用の分類器(classifier)が新たに1つ生成されて学習が開始されます。"Response Body" にはこの新たに作成された分類器を識別するための ID("classifier_id"、以下の例では "2374f9x69-nlc-8772") が含まれているのでメモしておきましょう。また現時点では "status" が "Training" となっていることもわかります。これは「この分類器はまだ学習が終わっていない状態である(問い合わせできる状態にはなっていない)」ことを意味しています。なので学習が完了するまではしばらく待つ必要があります:
2016070101


なお上記の curl コマンドを見ると、2つのファイルが multipart/form-data 形式でアップロードされていることがわかります。実際にこの部分を REST API で作る際には multipart/form-data で POST するように実装する必要がある、ということもわかります。またメタデータで指定した "name" ("dotnsf_nlc_demo")はこの API の実行結果に現れていることもわかりますね。


特定の分類器の学習が完了しているかどうかを確認するための API も用意されています。リストの1番下にある GET /v1/classifier/{classifier_id} という API です。この API を展開し、パラメータの classifier_id 欄に先程作成した分類器の classifier_id(この例では "2374f9x69-nlc-8772") を指定して "Try it out!" ボタンをクリックします:
2016070102


実行結果の "Response Body" を確認します。下の結果ではまだ "status" が "Training" となっていて、学習が完了していないことがわかります:
2016070103


しばらく(ケースバイケースですが、15~30分程度)待って、この API を実行し、"status" が "Available" となっていれば与えたデータの学習が完了したことになります。こうなると学習済みの分類器に対する問い合わせが可能になります:
2016070105


なお、この状態で再度最初の GET /v1/classifiers API を実行すると、(最初に実行した時の結果は空配列でしたが)先程新たに生成した分類器が実行結果に含まれて返ってくることがわかるはずです:
2016070104


さて、学習が完了したので、Watson NLC に問い合わせを実行してみましょう。リストの上から3番目の GET /v1/classifiers/{classifier_id}/classify か、または4番目の POST /v1/classifiers/{classifier_id}/classify を使って問い合わせを行います。この2つの違いは HTTP メソッド(GET か POST か)と、問い合わせテキストの送信方法(パラメータかリクエスト本文か)です。どちらでもいいのですが、今回は後者の POST /v1/classifiers/{classifier_id}/classify を使ってみましょう。

リスト内の POST /v1/classifiers/{classifier_id}/classify を選んで展開し、classifier_id に作成した分類器の classfier_id(この例では "2374f9x69-nlc-8772")を、body には Watson NLC に問い合わせさせたい日本語テキスト文書を、それぞれ入力します。

今回問い合わせるテキストは「RedHat だけでなく Ubuntu も勉強しないとね」というものにします(変更しても構いません)。この日本語の自然言語テキストを先程学習させた NLC に対して分類をリクエストし、学習時に与えたデータに基いて「学習データに使ったカテゴリでいえば、どのカテゴリに属するテキストであるか?そしてそれはどのくらいの確信度があるのか?」を問い合わせます。

なお body には JSON テキストを指定する必要があり、そのテンプレートが右側にあるので、その内容に沿って、以下のように body を用意する必要があることに注意してください:
{
  "text": "RedHat だけでなく Ubuntu も勉強しないとね"
}

2016070106


そして最後に "Try it out!" をクリックします。正しく実行されると、以下の様な JSON テキストが "Response Body" に返ってくるはずです:
2016070101


ちなみに "Response Body" の全文はこんな感じでした:
{
  "classifier_id": "2374f9x69-nlc-8772",
  "url": "https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/2374f9x69-nlc-8772",
  "text": "RedHat だけでなく Ubuntu も勉強しないとね",
  "top_class": "linux",
  "classes": [
    {
      "class_name": "linux",
      "confidence": 0.5345447969025622
    },
    {
      "class_name": "xml",
      "confidence": 0.17404873174100038
    },
    {
      "class_name": "cloud",
      "confidence": 0.09516428245259624
    },
    {
      "class_name": "opensource",
      "confidence": 0.07239515901217708
    },
    {
      "class_name": "web",
      "confidence": 0.0611971709641311
    },
    {
      "class_name": "java",
      "confidence": 0.04321802457711143
    },
    {
      "class_name": "mobile",
      "confidence": 0.019431834350421725
    }
  ]
}

実行結果に相当するのは上記の赤字部分です。これを表形式でまとめると以下の様な結果だった、ということになります:
分類結果順位分類結果確信度(%)
1linux53.45447969025622
2xml17.404873174100038
3cloud9.516428245259624
4opensource7.239515901217708
5web6.11971709641311
6java4.321802457711143
7mobile1.9431834350421725


1位は約 53.45% という確信度を以っての "Linux" でした。7つのカテゴリからの選択で 50% 以上の確信があるということはかなり高いと言えます。また人間の普通の感覚としても「RedHat だけでなく Ubuntu も勉強しないとね」というテキストの分類結果が Linux というのは、自然な(正しい)結果であるように感じます。 改めて注目していただきたいのは、問い合わせ本文には一言も Linux という単語はなかったのに、Linux という分類結果が高い確信度と共に得られている、という点です。


最後に、滅多に使わないかもしれませんが、作成した分類器が不要になった場合に削除する方法も紹介しておきます。リストの下から2番目にある DELETE /v1/classifiers/{classifier_id} を展開し、classifier_id パラメータに自分の ID(この例では "2374f9x69-nlc-8772")を指定して "Try it out!" をクリックします:
2016070102


実行が成功しました。が、成功した場合は特に "Response Body" には削除されたかどうかがわかる情報は含まれてない感じ:
2016070103


本当に消えているかどうかは、一番最初のステータス確認 API を再度実行して、classifier_id が消えていることを確認する必要があります。↓こうなっていれば消えています:
2016070101


以上、Watson API Explorer を使って NLC を体験してみました。NLC がどんなものか、なんとなく理解できましたかね。

まあ、個人的には「curl でやっちまった方が早いじゃん」とも思ってますが、コマンドラインに慣れない人もいるだろうし、こういう Watson API Explorer のようなウェブインターフェースが用意された背景にはそれなりの需要があったのではないかと考えています。加えて、ドキュメントと動作確認機能が統合されているのは確かに便利ですよね。



なお、NLC の API そのものの詳細については以下のリファレンスを参照ください:
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/natural-language-classifier/api/v1/


 

ダンジョン探索型 RPG の草分け的な存在でもある NetHack を CentOS にインストールしてみました。テキストキャラクターインターフェース RPG の元祖とも言える Rogue の後継で、いくつかの進化バージョンがありますが、今回紹介するのは UTF-8 に対応した日本語版 jNetHack 3.4.3 です。なお、今回導入した環境は CentOS 6.7 64bit ですが、(TTY 向けの導入しか紹介していないので)他の Linux ディストリビューションでもほぼ同様の方法で導入できると思います。


導入の方法ですが、現在は yum で簡単にインストール・・・ というわけにはいかないようで、必要なライブラリを揃えて、ソースコードを SVN からクローンして、パッチを充ててからビルドしてインストール、という手順が必要になるようです。以下にその手順を紹介します。

まずはビルド時に必要となるライブラリ群を yum で導入します。ここはコマンド一発:
# yum install -y libX11-devel ncurses-devel libXt-devel libXaw-devel

次に SourceForge から jNetHack のソースコードを入手し、更に UTF-8 対応用パッチを入手します。なお、以下の作業は全て /usr/local/src ディレクトリ以下で行うので、最初にこのディレクトリに移動しておきます:
# cd /usr/local/src

# svn co http://svn.sourceforge.jp/svnroot/jnethack/ jnh-svn
# wget http://elbereth.up.seesaa.net/nethack/jnethack-3.4.3-0.10-utf8-2.patch.bz2


ソースコードのディレクトリに移動し、UTF-8 パッチを適用します:
# cd ./jnh-svn/jnethack/trunk
# bzip2 -d /usr/local/src/jnethack-3.4.3-0.10-utf8-2.patch.bz2
# cat /usr/local/src/jnethack-3.4.3-0.10-utf8-2.patch | patch -p1

ビルド前に Linux 用にファイルを編集します。まず sys/unix/Makefile.top の該当業(青字部分)を編集します:
# vi sys/unix/Makefile.top

: # make NetHack PREFIX = /usr/local GAME = jnethack # GAME = nethack.prg GAMEUID = games GAMEGRP = bin # Permissions - some places use setgid instead of setuid, for instance # See also the option "SECURE" in include/config.h GAMEPERM = 04755 FILEPERM = 0644 EXEPERM = 0755 DIRPERM = 0755 :

次に sys/unix/Makefile.src の CLAGS を Linux 用に変更します:
# vi sys/unix/Makefile.src

: # flags for Linux # compile normally # CFLAGS = -O2 -fomit-frame-pointer -I../include : CFLAGS = -W -g -O2 -fomit-frame-pointer -I../include :

また include/unixconf.h 内で Linux 用の定義が一部無効になっているので、以下の4つをコメントアウトして有効にします:
# vi include/unixconf.h

: #define SYSV #define LINUX #define TERMINFO #define TIMED_DELAY :

同様に include/config.h 内の DLB の定義もコメントアウトして有効にします:
# vi include/config.h

: #define DLB :

これで準備は完了です。以下の手順で環境設定を有効にして、make all して make install します:
# cd sys/unix
# sh ./setup.sh
# cd ../../
# make all
# make install

なお、一度ゲームをスタートした後で、再度環境変更のビルドを行う場合、↑の最後のコマンドを make install から make update にすると、それまでのセーブデータを保護しながら本体だけをアップデートすることが可能です(make install だとセーブデータも上書きします)。

これで jNetHack が導入できました。jnethack コマンド本体は /usr/local/games/ にインストールされているので、フルパスで実行するか、このディレクトリにパスを通してください:
2016070301


実行時には UTF-8 対応の端末でログインし、この本体をコマンドラインから指定して実行します:
# /usr/local/games/jnethack

すると UTF-8 対応の jNetHack が実行されます:
2016070302


vi エディタでお馴染みの H,J,K,L による移動をベースとした RPG (の元祖)です。元々の Rogue が 1980 年に生まれたので、ゲームシステム自体は 36 年前から存在していることになります:
2016070303


NetHack 自体に関してはこちらの Wiki を参照ください:
https://ja.wikipedia.org/wiki/NetHack


 

HTTP2 に対応し、「デフォルト設定でも Nginx 並に速い」と噂の HTTP サーバー h2o を CentOS に導入してみました。

h2o は DeNA の奥氏を中心に開発されている HTTP サーバーです。h2o の誕生経緯に関してはこちらの資料にまとまっていたので、興味のある方は参照ください:
H2O - making HTTP better

h2o を CentOS にインストールする場合、現時点ではソースコードからビルドする必要があります。というわけで、まずはそのための前提ライブラリを導入します:
# yum groupinstall "Development Tools"
# yum install curl curl-devel libarchive libarchive-devel expat expat-devel zlib zlib-devel openssl cname
# rpm -Uvh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
# yum install libyaml-devel --enablerepo=rpmforge

その後、h2o のソースコードを git clone して、make して、ビルドして、インストール:
# cd /usr/local/src
# git clone https://github.com/h2o/h2o.git
# cd h2o
# cmake -DWITH_BUNDLED_SSL=on .
# make h2o
# make install

設定ファイルを用意します。今回はシンプルにこんな内容にしました:
(/usr/local/src/h2o/examples/h2o/h2o.conf の中身)

listen: 8080
hosts:
  default:
    paths:
      /:
        file.dir: examples/doc_root
    access-log: /dev/stdout

設定ファイルが用意できたら実行します。本体は /usr/local/src/h2o/h2o で、実行時に -c パラメータで設定ファイルを指定します:
# cd /usr/local/src/h2o
# ./h2o -c examples/h2o/h2o.conf

今回は 8080 番ポートで起動するような設定ファイルを用意したので、動作確認には 8080 番ポートへアクセスします:

2016063001
 ↑動いてます


このページのトップヘ