Juman, KNPのカテゴリ情報を加える

文章のprolog二分木化に際して、juman, knpが吐き出す語のカテゴリ情報を加えることにした。意味カテゴリにどんなものがつくかは、こちらが参考になる。ただ、juman++のものだが、jumanのものが見つからなかった。多分、同じようなものだろうと思う。

カテゴリがわかると、言葉の使い方に大きな力になる。カテゴリがばその言葉XXには、「XXに行く」という表現が成立するが、食べ物YYには「YYに行く」という表現は成り立たない。代わりに、「YYを食べる」は成り立つが、「XXを食べる」は、比喩としてしか成立しない。

逆にそれは、お笑いのボケ的には成立する。「XXを食べた」はボケであり、「そんなもの食べてうまいか!」というツッコミも成立する。

prologの宣言文(二分木)を作成するプログラムには少し手間取ったが、「羅生門」の一節は、例えば、次のような感じで変換される。

plsample(line0_7,
    node(だから,
        [],
        node(を,
            node(が,
                [[下, '場所-機能'], [人, 人]],
                [[雨, 抽象物], [やみ, 抽象物]]
            ),
            node(いたと,
                [待って, 待つ],
                node(よりも,
                    云う,
                    node(に,
                        [雨, 抽象物],
                        node(られた,
                            [ふりこめ, ふりこめる],
                            node(が,
                                [[下, '場所-機能'], [人, 人]],
                                node(に,
                                    node([],
                                        node(が,
                                            [行き, [所, '場所-施設']],
                                            なくて
                                        ),
                                        [途方, 抽象物]
                                    ),
                                    node(いたと,
                                        [くれて, くれる],
                                        node([],
                                            云う,
                                            node(が,
                                                方,
                                                node([],
                                                    適当である,
                                                    [ ]
                                                )
                                            )
                                        )
                                    )
                                )
                            )
                        )
                    )
                )
            )
        )
    )
).

例えば、6行目に、下人がある。jumanが下人を形態素解析で、下と人に分けてしまう。そこはそれとして問題だが、下は場所であり、人は人というカテゴリに属するという情報を、prologのリストにして組み込んでいる。

名詞にカテゴリが付与されている場合は、[下, '場所-機能']のように、その表示語とカテゴリが一対になったリストになる。この場合は、'-'が間に挟まれているので、prologがAtomとして正しく処理されるようにアポストロフィ「'」で囲んである。カテゴリを持っていなければ、表示後だけになる。一方、動詞は、[待って, 待つ],のように、表示語と原型が一対になっている。原形がなかったり、表示語と原形が同じ場合は、表示語だけになる。

例えば、「下人が雨やみを待っていた」をjumanを経由してknpにかけると、次のような結果(-simple) を出してくる。

# S-ID:1 KNP:4.19-CF1.1 DATE:2019/03/17 SCORE:-21.54059
* 2D <体言>
+ 1D <体言>
下 した 下 名詞 6 普通名詞 1 * 0 * 0 "代表表記:下/した 漢字読み:訓 カテゴリ:場所-機能" 
+ 4D <体言>
人 じん 人 名詞 6 普通名詞 1 * 0 * 0 "代表表記:人/じん 漢字読み:音 カテゴリ:人" 
が が が 助詞 9 格助詞 1 * 0 * 0 NIL 
* 2D <体言>
+ 3D <体言>
雨 あめ 雨 名詞 6 普通名詞 1 * 0 * 0 "代表表記:雨/あめ 漢字読み:訓 カテゴリ:抽象物" 
+ 4D <体言>
やみ やみ やみ 名詞 6 普通名詞 1 * 0 * 0 "代表表記:闇/やみ カテゴリ:抽象物" 
を を を 助詞 9 格助詞 1 * 0 * 0 NIL 
* -1D <用言:動>
+ -1D <用言:動><格解析結果:ガ/人;ヲ/やみ;ニ/-;デ/-;ヨリ/-;時間/-;ノ/->
待って まって 待つ 動詞 2 * 0 子音動詞タ行 6 タ系連用テ形 14 "代表表記:待つ/まつ" 
いた いた いる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 タ形 10 "代表表記:いる/いる" 
EOS

ここで、*から始まるものを、私は「句 phrase」と定義している。したがって、複数の「語」が「句」を作り、複数の「句」が文章を作るということである。この文章を、prolog化すると次のようになる。

%% phrases: [ 0 r1 2 ] 
plsample(line0_0,
    node(を,
        node(が,
            [[下, '場所-機能'], [人, 人]],
            [[雨, 抽象物], [やみ, 抽象物]]
        ),
        node(いた,
            [待って, 待つ],
            [ ]
        )
    )
).

最初の文章は、prologのコメントでしかなくて、以下のものが第二句をルートフレーズとして、二分木が作成されたことを示している。(この辺りは以前の記事で詳細に解説したが、少し繰り返しの説明になっている。細かく知りたい場合は、過去の記事にあたっていただきたい)

ツリーで表すと次の画像のようになる。

最後の語は、ここでは、空リスト [ ]になっているが、必ずしも、そうなるわけではない。この辺も、過去の記事をいていただきたい。

少し過去を振り返る回り道をしたが、その理由は、句に注目していただきたかったからだ。ここでは、最初の句は、「下人が」になる。jumanは「下」と「人」と「が」という、三つの語でこの句を構成していると形態素解析した。最初に「下」という名詞で、[下, '場所-機能']というカテゴリとのペアのリストを作成して、さらに次に、「人」という語が来たので、[人, 人]というペアリストを作成して、それを前の[下, '場所-機能']と繋げたのであるが、これをprologで処理可能なように、それらをリストとして繋げて、[[下, '場所-機能'], [人, 人]]にした。これをリストにしないと、それらが二分木の左右の葉と解釈されて、次に来る右葉にとの関係で、エラーを引き起こしてしまう。

もし、語「下」にカテゴリがなかったら、これは、カテゴリを持たない単独語となり、次いの「人」が現れた時に、結局リストは、[下, [人, 人]]と構成されることになる。

もし[[下, '場所-機能'], [人, 人]]を作成した後に、同じ句内に別のもう一つの名刺とカテゴリがあって、[菓子, '人工物-食べ物']というリストを作ったら、これらは、

[[下, '場所-機能'], [人, 人],[菓子, '人工物-食べ物'] ]

という、それまでの中に、三つ目のリストとして組み込まれるのではなく、

[[[下, '場所-機能'], [人, 人]],[菓子, '人工物-食べ物']]

と、新たに、全体を囲むリストを作って、その中に収められる。どう違うのか?ちょっと、分かりにくいが、つまり、要素が上の場合のように三つになることはなく、一つのリストの中の要素は、リストか単独語の二つの要素しかないということである。結局これも二分木になっているのである。

図に描くと上のようになる。

短文の要約のアイデア

一つの文章をさらに短くすること、ここをもう一つ高いレベルでクリアしたい。知識は言葉の定義で与えられるとして、それはなんとか使える。が、舞台でしゃべる言葉はごく短くなければならない。一応、そのシステムは作ってあるが、短くした後の言葉が、理解のしやすいものに必ずしもなっていない。

私が目標とするところからして、今、芸ロボットの到達点は50%くらいだと思っている。もし、短文要約が大きな問題なく、人と同じくらいのレベルでできるようになれば、この到達点は70%くらいまでいくだろう。

ではどうすれば良いのか。一つ頭に浮かんでいるのが、ようやく対象が含む語の主要なものが含まれている、より短い文章の用例を探すことだ。ただ、全く同じ語については、あるかもしれないが、探すのが大変すぎる。

そこで、言葉をグループ化する。例えば、りんごとバナナは、果物というグループに属するので、「デザートには〇〇が出た」という文章の〇〇には、等しく使える、置き換えられる。他の「ラーメン」という言葉は、この〇〇にはめることはできない。また、さらに広く、食べ物というグループにも属しているので「彼は〇〇を食べた」の〇〇にも同じように使える。この場合は、ラーメンという言葉もはめることができる。

適用可能な言葉は、ある種の階層性を持っているのである。

このグループ化、階層性を表現するために、類語辞典を使うことができる。類語辞典のコード番号を用いて、日本語ウィキペディアの前文章を用例化する。

そして、ある長い文章が与えられ、そこで使われている用語の重要性について、指標が与えられているとして、コード化した同じ語のグループが使われている用例を拾い出す。ただし、短くする程度に応じて、元の語のいくつかを削ったものにしていく。

コード化した語で、短い用例があれば、それで文章を再構成すれば、単文が要約できることになる。

というアイデアである。

アイボット株式会社決算と納税申告

このサイトのURLは、http://www.ibot.co.jp/wpibot/で、ibot.co.jpはアイボット株式会社が取得しているドメインだ。この会社は、私が2014年にロボット関係サービスと関連商品の販売のために設立した会社で、現在は妻が社長で、私は単なる出資者だ。大学の兼業との関係でそうしている。実質、何も事業活動していない。

ただ、事業活動をしていなくても、都税の均等割分7万円を毎年払っていた。が、こう完全に何もしていないのに7万円は負担だ。もう、私も大学を辞める時期が近づいているので、こんな余計な金を払うくらいなら、廃業しようと、昨夜布団に入りながら考えていた。

こう思うのは、決算書を書かなければいけない時期だからでもある。この10月31日で、第4決算期が終了するので、2ヶ月以内に決算をして、税申告を国と東京都に対してしなければならない。何もしていないので、減価償却処理などをすれば簡単に決算書はかけるのだが、お金の負担が痛い。

解散すると、多分、このibot.co.jpも返上しなくてはならなくなる。それは大したことはないのだが、残念であることは変わりない。

それでも、今朝、法人解散を考えて、ネットを調べていると、株式会社の解散もそう簡単ではない。法務局に二回手続きをして、自分でやっても7万円くらいのコストがかかる。ましてや、業者にやってもらうと、その倍以上の手数料がかかってくる。

ネットで調べているうちに、会社を休業して、手続きすれば、均等割分を回避できる可能性があることを知った。早速、今朝、都税事務所に電話して、どうすれば良いかを教えてもらった。

(1)国税の申告書を出して別表の1というのをもらう。これはいつも控えとしてもらえるものだ。
(2)都税事務所の提出書類の他に、決算書も提出する。
(3)と税の申告書のどこでもいいが「休業中」と記載する

これを活動していないときは、毎年手続きを取れば良いらしい。これで絶対課税を免れるわけではないようだが、もし課税されるときは、事前の電話連絡があるらしい。ただ、アイボット株式会社は、ほぼ完全な休眠会社なので、多分、課税手続きは行われないと思っている。

前から、この会社のことは頭痛の種だったが、これでとてもスッキリした。毎年申告しなければならないが、それは大した手間ではない。

またいつか、本当にこの会社を動かしたくなる時も来るだろう。その時まで、待機させていると考えることもできる。

よかったよかった。

サイトが極端に重たくなるので調整した

サーバーが重くなるので設定を変更した。

StartServers       8
MinSpareServers    5
MaxSpareServers   20
ServerLimit      256
MaxClients       256
MaxRequestsPerChild  4000
MaxMemFree 1024

あまり効果がなかったので、さらに、

StartServers        4
MinSpareServers     2
MaxSpareServers    10
ServerLimit       128
MaxClients        128
MaxRequestsPerChild 30

と変更して、様子を見る。

Netbeansを9.0にした

何もかも、Java頼みだ。ロボット即興漫才のシステムは、ロボット内のシステム(ライブラリ)は、C++、コントローラーはHtml5(Javascript)、アプリケーションレベルは全てJavaだ。

JavaとHtml5の開発は、Netbeans頼みなのだ。久しぶりにバージョンアップした。apacheからダウンロードするようになった。これからは、apacheのnetbeansに慣れていかなければならないので、使うようにしようということだ。

https://netbeans.apache.org/download/index.html

ここからダウンロードしてインストールすれば良い。私の場合、macなので、少し違っているが、

https://github.com/carljmosca/netbeans-macos-bundle

から、ダウンロードして、スクリプトを実行すれば、今までにない、カラフルなnetbeansのスプラッシュが現れて実行される。

日本語wikipediaにおける助詞・助動詞の使用頻度

先のいくつかの記事で示しているように、ロボットが知識的文章を短く語る時に、削除した語を繋ぐ助詞をAI的に選択させようとしている。(体言1:名詞・動詞)+(助詞1:助詞・助動詞)+(体言2:名詞・動詞)+(助詞2:助詞・助動詞)の語の並びの中で、体言1、体言2、助詞2が与えられた時に適切な、助詞1を選択させたい。これができれば、うまく、文章を短くできるだろうということである。

そこで、この並びを、日本語wikipediaの前文から拾い出して、それを元に、ディープラーニング用の学習データを作ろうということである。

4語対は、6千万個取れて、語は、word2vecのウェイトベクトルであらわすのだが、そのベクトルを取れる語は、さらに半分以下になってしまう。また、助詞、助動詞部分のパーターンがとてつもなく大きくなってしまう。「の」とか「を」などはたくさんあるが、全体で1回しか現れないようなものも拾ってしまう。これは、広い方のアルゴリズムにも依存するのだが。

そこで、いったいどのような助詞、助動詞が、どのような頻度で現れているのかを調べてみた。

まず、助詞2(ニューラルネットの入力になる)は次のようになっている。

の 	4848543
を 	3418017
に 	3153274
が 	2271523
は 	1676994
と 	1359190
で 	1134953
た 	833487
な 	515517
から 	481586
や 	449712
も 	403445
て 	391692
である 	384000
として 	321609
ている 	278220
には 	264654
では 	242007
ていた 	141653
によって 	117531
であり 	109701
により 	109549
であった 	107166
による 	101919
へ 	97715
でも 	97698
との 	95020
という 	95008
まで 	94623
への 	88007
にも 	87645
ない 	80116
での 	77605
たが 	71719
だった 	71462
など 	69269
ており 	69104
だ 	68336
ず 	64151
などの 	62250
より 	56385
とは 	53537
において 	50758
たと 	47488
からの 	46761
における 	45079
について 	38801
ば 	34365
たり 	33421
に対して 	32896
なかった 	32558
はと 	31786
としては 	31599
か 	31034
に対する 	30519
であると 	30483
としての 	30440
うと 	30412
とも 	29750
とともに 	29742
ていたが 	29645
だが 	29500
などを 	28746
までの 	28607
ながら 	27353
と共に 	26439
へと 	25588
に関する 	25518
だと 	25209
よりも 	24233
であるが 	24219
などが 	23941
ではなく 	23687
については 	23225
であったが 	21177
ているが 	20375
にて 	20046
てきた 	19284
でいる 	19168
からは 	19166
ても 	18992
ていない 	18033
などで 	17049
に対し 	16993
といった 	16725
だったが 	16552
をと 	16238
ていく 	15419
などに 	15401
ていると 	15107
てしまう 	14659
までに 	14412
にと 	14395
においては 	13755
でいた 	13566
ずに 	12898
のみ 	12697
なく 	12433
たものの 	12417
にかけて 	12292

明らかに、代表的助詞型を圧倒している。だから、全部を対象にすることはない。だいたい、上位128個くらいの使い方がわかればそれでいいのではないかと思う。入力に関しては次のようになっている。

の 	6087401
は 	2794515
に 	2311801
を 	1850357
が 	1667993
で 	1144968
と 	1039936
た 	1026311
な 	563759
や 	531865
から 	515033
て 	502233
には 	461876
では 	405320
も 	340662
である 	297177
として 	239221
ている 	200314
という 	145218
であり 	141251
ていた 	140480
との 	135622
により 	135543
による 	124273
への 	116794
での 	114556
たが 	110351
によって 	100663
まで 	99795
などの 	99002
ており 	98666
など 	95691
でも 	91841
ず 	91712
とは 	87425
であった 	78465
ない 	76015
にも 	73529
より 	69404
だ 	67224
において 	65830
からの 	63813
における 	59617
だった 	59331
ば 	53503
へ 	50134
としての 	44902
に対する 	40913
に対して 	40079
だが 	39554
としては 	38818
に関する 	37624
について 	37003
ていたが 	36863
までの 	35317
とともに 	33629
からは 	33043
ながら 	32942
たり 	31465
であるが 	31366
については 	30835
と共に 	30434
か 	28826
はと 	28675
ではなく 	27939
なかった 	27507
といった 	26896
などを 	25960
に対し 	25781
であったが 	25642
よりも 	24764
においては 	24509
ているが 	24095
ても 	22715
にかけて 	22410
にて 	22061
とも 	20988
だったが 	20078
てきた 	18660
までは 	15710
はの 	15630
などで 	15530
たものの 	15429
などが 	15169
うと 	14569
へと 	14314
までに 	14160
にとって 	13547
ていない 	13388
たという 	13324
でいる 	12949
ずに 	12844
についての 	12823
のの 	12695
でいた 	12154
ので 	12077
ほど 	11709
のみ 	11541
であると 	11315
だと 	11167
はという 	11122
がと 	11042
をと 	11024
ていく 	10883
てしまう 	10794
などに 	10719
においても 	10605
にと 	10454
を通じて 	10373
たと 	9804
だけでなく 	9448
ての 	9116
しか 	9065
にの 	9027
によっては 	8952
かの 	8682
であるという 	8620
に関しては 	8216
てしまった 	8172
ほどの 	8126
ていて 	8058
はなく 	8000
からも 	7909
ては 	7779
てくる 	7631
てから 	7518
にという 	7329
つつ 	7309

上位グループの順序は微妙に変わっている。助詞の位置が影響しているのだ。が、上位グループのメンバーはあまり変わらない。

助詞推定AIの改訂(1)

ロボットが知識データを言い換える時に、助詞を適切なものに切り替える必要があり、前後の体言や助詞からそれを推計するシステムを作ったと、先の記事で書いた。そのシステムを、いざ、即興漫才システムに組み込もうとした時に、いくつか問題が起こって、最初のデータから作り直すことにした。

まず、助詞だけにして助動詞を対象から外していたのを、加える必要がある。名詞や動詞が連続する場合、1語として扱えるようにする。助詞、助動詞も連続して現れる可能性があるので、それも対応する必要があった。

データ作成は、まず、日本語wikipediaから、元データを作成する。基本的に、文章の中にある、

体言1(動詞、名詞) → 助詞2(助動詞も)→ 体言3→ 助詞3(助動詞も)

という4つの語の流れを拾ってくる。例えば、次のようなものである。

肥満::は::一般的::に
一般的::に::正常::な
正常::な::状態::に
状態::に::比べ::て
比べ::て::体重::が
体脂肪::が::過剰::に
過剰::に::蓄積し::た
蓄積し::た::状況::を

ある生存中::の::当事者同士::が
当事者同士::が::有効::に
有効::に::成立し::た
成立し::た::婚姻::を
婚姻::を::婚姻後::に
婚姻後::に::生じ::た
生じ::た::事情::を
事情::を::理由::として
理由::として::将来::に
将来::に::向かっ::て
向かっ::て::解消すること::を

ペットボトル::は::合成樹脂::の
合成樹脂::の::一種::である
一種::である::ポリエチレンテレフタラート::を
ポリエチレンテレフタラート::を::材料::として

パンダ::は::ネコ目::に
ネコ目::に::属するジャイアントパンダ::と
属するジャイアントパンダ::と::レッサーパンダ::の
レッサーパンダ::の::2種::に対する
2種::に対する::概念上::の
概念上::の::総称::である

この助詞1を体言1、体言2、助詞2から推計しようというのである。後者をword2vecのベクトルデータを用いるなどして入力データに変換して、出力が助詞1のいずれかに推計する。

上記の4語のデータを、日本語wikipediaデータについて、すべてやる。日本語wikipediaデータは、word2vecの時に使用下処理済みデータを用いる。

24スレッドをフル稼働させるプログラムにしたら、10分程度で、全データを処理終えて、4つの語の組み合わせを、63,600,830個拾い出してきた。6千万個以上である。すごい。データは、2ギガくらいのファイルに保存んした。

ディープラーニングのプログラムを組み直す(2)

相当基本的なところから組み直した。ごちゃごちゃしたプログラムをだいぶ整理した。直しはバグのもとであり、結局、MNISTの手書き文字の認識まで戻ってテストせざるを得なくなった。

ディープラーニングのエンジンである、バックプロパゲーションのところだけは、流石にいじらなかった(笑)ここをいじり始めたら収拾がつかなくなる。

以前は、学習とテストを同じ関数でやっていたが、きちんと切り分けた。CUIからGUIにインターフェイスをレベルアップさせた。

かなり拡張性も出てきたと思う。MNISTの正解率も以前のものと同じものに戻った。オブジェクトというか、クラスをかなり整理したので見やすいプログラムになったと思う。

これで、最適助詞選択プロジェクトに入る。

twitter データを最初から作り直す

この間、twitterやwikipediaのウェイトデータをmariadbのデータベースにしたり、言葉の距離の近いものをリストする場合のデータを事前作成したりしたが、データ量を減らすために、4文字以上のアルファベットのある言葉を排除してきたり、全てがアルファベットの言葉を排除したりした。この制約が、いろいろ面倒なことになってきた。ので、全て作り直す。10時間くらい浪費するような気がする。

Twitterデータは、その後集めたデータも含めて、最初のコーパスから作り直す。結局、利用する総ツイート数は、
25,188,425ツイート
になった。まだ1億個までは程遠い。ので、毎日せっせと収集スクリプトを動かして集めている。24時間動かし続けて、100万個程度集まるので、1ヶ月かけても1000万しか集まらない。スレッドを複数にして集めようとしたが、結局、twitterがサンプリングしているのは同じのようで、同じものを複数買い集めていることにしかならないので、一個のプログラムでひたすら集めている。

word2vecのdistanceで、入っている任意の言葉のすべてについて、相互の距離を計算するので、計算量は膨大であり、自宅の12コア、24スレッド動くmacで20スレッド程度を並列で動かしてまず、テキストデータを作成し、それを次にmariadbに登録する。

テレパシーでデータを受け取るときの仕様の変更

M-1目前で、昨日からグダグダになっている。その詳細は、余裕がないのでまたいずれ。

ここで、記憶のために書いておくことは、サリーやハル、あるいはそれぞれ同士の間でメッセージをやり取りする場合に、telepathyというプロトコルを使用している。元々は、qichatで制御されるnao同士の間でのやり取りの仕様として開発したが、その後、emilyを積んだhal型のロボットと規格を統一してやり取りできるようにしている。

基本、相手のイベントを発生させるような信号を送るシステムだったが、さらに、メッセージも送れるようにした。送られたメッセージは、$telepathy_dataという変数に自動的に格納されるようにしていたのだが、ここにきて、同時に複数のデータを送るときに、同じ、$telepathy_dataに入れておくと、当然バッティングしてしまう。

だから、以後発生させるイベント名に_dataを付けた変数に格納する。例えば、telepathy_hal_subjectというイベント発生を相手の求めた場合、それにつけている「お題は」(実際は、ネットワークの制約からurlencodeしたものを送っている)というデータは、
$telepathy_hal_subject_data という変数に格納される。こうすれば、同じイベントで違うデータを送ろうとしない限りバッティングしないし(これはあり得ない、訂正とかであり得るかもだが)、やり方も覚えやすい。

naoの組み込みライブラリーの改訂が必要になる。ああ、面倒。

システムが、ハードとソフトにまたがって複雑すぎて、覚えられなくなっている。ので、せめてここに書いて、記憶の助けにする。