IMAKITA for nodejs

IMAKITA for nodejs


2020/09/27(初版)
2021/01/05(改訂)
藤田昭人


対話機能の話、まずは道具立てから…

もちろん「書籍やブログと(擬似的に)対話する」がコンセプトのBookBotの場合、 返事はできるだけ書籍からの文章をそのまま使いたいところです。 書籍の中から話しかけられた質問に答えている箇所(たぶん、どこかの文節になると思いますが)を探し出せたとして、 それをギュッと一言にまとめる自動要約の機能が必要になります。

本稿ではそのためのアルゴリズのIMAKITAを紹介します。


抽出型文書要約アルゴリズム IMAKITA

この名前、日本語の音感を感じるので、最初は「なんの語呂合わせ?」と思ったのですが、 Importance Aligned Key Iterative Algorithm (IMAKITA) と言うことのようです。

この自動要約アルゴリズムGIGAZINEの次の記事を見つけました。 これは日本語文の要約結果が日本語として整っていることを期待して 「日本人が開発した自動要約アルゴリズム」を条件に探しまくった結果です。

gigazine.net

この記事、用例として「くろがね四起」だとか「松浦雅也*1だとかが出てくるので、 「これならオタク的文章でもいけるかも…」と考えた次第です。

開発者が書いたショートメモはこちら。 オリジナルは Python バージョンだったようです。

qhapaq.hatenablog.com

…が、その後 Chrome 拡張バージョンも公開されました。

qhapaq.hatenablog.com

こっちはもちろん JavaScript で書かれていますし、ソースも公開されています。 ソースを見るとこのバージョンは日本語と英語に対応しているみたいです。 論文によれば、自動要約には 抽出的要約(extractive summarization)と 抽象的要約(abstractive summarization)があるそうでが、 IMAKITAは抽出的要約を採用しているので、 マルチリンガルに(容易に)対応できるとのこと。

本稿では、この IMAKITA on Chrome をベースに以降の話を進めます。


IMAKITA for nodejs

もちろん Chrome 拡張された IMAKITA は便利なんですが、 このままでは nodejs では使えないのでヘッド部分を nodejs 用に書き換えました。 以下の手順でオリジナルコードにパッチを当てることができます。

1.IMAKITA on Chrome のコードをダウンロードする

GithubIMAKITA on Chrome のページからコードをダウンロードします。 Download ZIP が便利。

2.ソースファイルを取り出す

ダウンロードしたコードから、 preproc_ja.jsimakita_body.jstiny_segmenter-0.2.js を取り出します。

3.ソースファイルにパッチを当てる

preproc_ja.jsimakita_body.js については nodejs 向けに修正が必要です。
次のパッチを当ててください。

$ diff -u imakita-master/preproc_ja.js imakita4nodejs/preproc_ja.js
--- imakita-master/preproc_ja.js    2019-05-22 21:02:31.000000000 +0900
+++ imakita4nodejs/preproc_ja.js    2021-01-06 08:15:08.000000000 +0900
@@ -5,6 +5,9 @@
    m[a] = (m[a] || []).concat(i);
    return m;
     }, {});
+
+  const TinySegmenter = require('./tiny_segmenter-0.2');
+  const imakita = require('./imakita_body');

     var segmenter = new TinySegmenter();
     var word_weight = {};
@@ -24,7 +27,7 @@

     for(var i=0; i<sentences.length; ++i){
    var word_list_temp = segmenter.segment(sentences[i]);
-   console.log(word_list_temp);
+   //console.log(word_list_temp);
    var sens = {"id":i, "word_list":[], "importance":0};
    for (var j=0; j< word_list_temp.length; ++j){
        if (!(word_list_temp[j].toLowerCase() in not_word)){
@@ -42,13 +45,13 @@
    sens_list.push(sens);
     }

-    set_importance(sens_list, word_weight, word_list_minimum);
+    imakita.set_importance(sens_list, word_weight, word_list_minimum);
     /*
     console.log(sentences);
     console.log(sens_list);
     console.log(word_weight);
     */
-    var summary_id = binary_search(sens_list, word_weight, summary_number, 5);
+    var summary_id = imakita.binary_search(sens_list, word_weight, summary_number, 5);
     //console.log(summary_id);
     var summary_txt = []
     for (var i=0; i<summary_id.length; ++i){
@@ -58,3 +61,4 @@
     return summary_txt;
 }

+module.exports = preproc_ja;
$ diff -u imakita-master/imakita_body.js imakita4nodejs/imakita_body.js
--- imakita-master/imakita_body.js  2019-05-22 21:02:31.000000000 +0900
+++ imakita4nodejs/imakita_body.js  2021-01-05 11:56:23.000000000 +0900
@@ -114,3 +114,8 @@
     });

 }
+
+module.exports = {
+  binary_search:  binary_search,
+  set_importance: set_importance
+}
$ 


IMAKITA for nodejs を試してみる

サンプルプログラムを示します。テストデータは 「対話分野の研究をしたいときに気をつけたいこと」 から冒頭部分を借用しました。

var sections = [
  '身近なものに対話システムを組み込もうとする流れが来ているのか、機械学習の性能向上や、データの充実などの研究地盤が整ってきたのか、対話システムの研究が暖かみを帯びてきました。\n私はここ数年対話系の研究面白そうだなぁとなり、昨年度辺りから(突発的に卒業研究をしなければならないという話もあり)論文読みや実験を行っているのですが、この研究・発表など大変苦労したので、同じ轍を踏まないようにここに色々書いておこうと思います。\n尚、この分野は皆さんが想像している以上に広いので、どんなに頑張ってもこの手の解説は一説の域を出ることができないことを補足しておきます。(逆に、これが対話分野の研究のすべてだ!と言っているテキストなんかは注意したほうが良いと思います。自分は大分痛い目を見ました。)'
];


const preproc_ja = require('./preproc_ja');

var summary_number = 3;
var minimum_length = 10;
var separator = [". 。 .","\n . 。 ."];

for (var i = 0; i < sections.length; i++) {
  var summary = [];
  summary = preproc_ja(sections[i],
               summary_number,
               minimum_length,
               separator);
  console.log("------\n%s\n------\n", sections[i]);
  for (var j = 0; j < summary.length; j++) {
    console.log("\n%d: %s。", j, summary[j]);
  }
}

preproc_jaの引数の意味は次のとおりです。

引数 説明
(text) 要約対象の文章
summary_number 生成する要約文の数
minimum_length 要約文の最小文字数
separator 文を区切る文字

このプログラムを実行すると次のような結果が表示されます。

$ node summarization.js
------
身近なものに対話システムを組み込もうとする流れが来ているのか、機械学習の性能向上や、データの充実などの研究地盤が整ってきたのか、対話システムの研究が暖かみを帯びてきました。
私はここ数年対話系の研究面白そうだなぁとなり、昨年度辺りから(突発的に卒業研究をしなければならないという話もあり)論文読みや実験を行っているのですが、この研究・発表など大変苦労したので、同じ轍を踏まないようにここに色々書いておこうと思います。
尚、この分野は皆さんが想像している以上に広いので、どんなに頑張ってもこの手の解説は一説の域を出ることができないことを補足しておきます。(逆に、これが対話分野の研究のすべてだ!と言っているテキストなんかは注意したほうが良いと思います。自分は大分痛い目を見ました。)
------


0: 身近なものに対話システムを組み込もうとする流れが来ているのか、機械学習の性能向上や、データの充実などの研究地盤が整ってきたのか、対話システムの研究が暖かみを帯びてきました。

1: 尚、この分野は皆さんが想像している以上に広いので、どんなに頑張ってもこの手の解説は一説の域を出ることができないことを補足しておきます。

2: (逆に、これが対話分野の研究のすべてだ!と言っているテキストなんかは注意したほうが良いと思います。
$

5行の文章を3行に要約するのでは意味がないので summary_number を1にしてみたら…

$ node summarization.js
------
身近なものに対話システムを組み込もうとする流れが来ているのか、機械学習の性能向上や、データの充実などの研究地盤が整ってきたのか、対話システムの研究が暖かみを帯びてきました。
私はここ数年対話系の研究面白そうだなぁとなり、昨年度辺りから(突発的に卒業研究をしなければならないという話もあり)論文読みや実験を行っているのですが、この研究・発表など大変苦労したので、同じ轍を踏まないようにここに色々書いておこうと思います。
尚、この分野は皆さんが想像している以上に広いので、どんなに頑張ってもこの手の解説は一説の域を出ることができないことを補足しておきます。(逆に、これが対話分野の研究のすべてだ!と言っているテキストなんかは注意したほうが良いと思います。自分は大分痛い目を見ました。)
------


0: (逆に、これが対話分野の研究のすべてだ!と言っているテキストなんかは注意したほうが良いと思います。
$

ちゃんと一番大事な文が残りました。


さいごに

無作為に選んだ文章を、 まるでその意味を理解しているかのように要約するIMAKITAの実力に 正直ちょっとビックリしたのですが…

これがWord2vecに代表されるベクトル空間モデルのトリックなんでしょうね。

種明かしは、いずれまた…

以上

*1:松浦雅也の紹介で PSY・S が出てこないってどう言うこと?