28-Sep-2023
[ちまちまと]

nwc2010-libkkcの作業が収束しなくて、「ヴ」を含む単語の処理が全然できていなかったとか、JUMAN対応を入れてはみたもののあまりの遅さに使い物にならないのでこれを投げ捨ててChaSen対応を入れてみたとかそんなことやってました。あんまり機能追加しちゃうとOpenBSD上で動かす際に(それぞれのエンジンを動かすところから始めないといけないので)色々面倒なことになるのですが…当面はdata.arpaを得るところまではLinux上でやれば良いと割り切ることにします。

…で。

nwc-toolkit、これを動かせるようにするのがまあ面倒で。現時点ではGoogle Codeにあるnwc-toolkit-0.0.2.tar.gzと、GitHubにあるxen/nwc-toolkit(おそらく本家からforkしたと思われる)があり、xen版はv0.1.0ということになっているようです。どちらを使うかについては、xen版のnwc-toolkit-0.0.2ブランチとnwc-toolkit-0.0.2.tar.gzを比較すると違いはなかったのと、nwjc2vec:『国語研日本語ウェブコーパス』 に基づく単語の分散表現データ(言語処理学会第23回年次大会発表論文集(2017年3月)・浅原正幸・岡照晃)(PDF)に0.0.2を使ったとの記述があるので、0.0.2を使うことにしました。とはいえ、論文の脚注にnwc-toolkitが現在公開停止と書いてあるのは一体どういうことなのかというのは気になるところです。

とりあえずソースコードを展開して、Debian-12/amd64で./configure; make…できません。<iconv.h>はあるのにlibiconvが無いと言われてしまいます。そもそもglibcはlibiconvを取り込んでいるのでlibiconvが無くても問題は無いはずです。autotools(autoconf, automake)で使うファイルをいじってコンパイル自体はできるようになるものの、シンボルを解決できないためにオブジェクトを作れない問題が直せなかった(ライブラリのリンク順を変えれば済む問題なのだけどこれがどうにもできなかった)のでCMake化してしまいました。ビルドができるようになったとしても、動作するかどうかは別途試す必要があります。面倒なのであまりやりたくないんですけど。

それにしても…このコードは随分と長い間うち捨てられていたコードですねえ。この程度の修正で動かせるようになるなら誰でもできるので必要になった時にやれば良いという考えなのかもしれませんが、論文の作成に使ったツールくらいはきちんとした形で公開を続けていてほしいものですし、必要最低限のメンテナンスも続けて頂きたいものだと思ってしまいます。とはいえ、nwc-toolkitを使用した最近の事例としてNWJCの文抽出(文選択)(2023-04-04)がありますし、実は自分のソースコードの扱い方が根本的に間違っていたのではないかという気もしています。55.7kg(22:55)

23-Sep-2023
[kakasiだけでなく]

MeCabでも読み仮名を付けられるよう、nwc2010-libkkcを改造してみました。Cを使っていた人間がC++を使うようになったばかりなので、C臭さの抜けないC++コードになっていますが…Cだとやりにくいことが容易にできるという点でC++はなかなか便利だなあと実感しているところです。

MeCab版のdata.arpaでは辞書を作っていないので、使用感は分かりません。読み仮名を付加した3-gramデータや生成されたdata.arpaを見るに、kakasiとは若干違う出来になっていますのでどちらが良いかは使う人の好みになりそうです。

MeCabとChaSenの出力フォーマット(2011-01-02)において、MeCabは「開いた口が塞がらない」を「ひらいたくちがふさがらない」と解釈しています(kakasiやJUMANでも同様の結果になることを確認しています)。本来なら「あいたくちがふさがらない」となってほしいのですが、機械的に読みを当て嵌めている以上、この辺りは上手くいかないのかもしれません。人力で読み仮名を振ったコーパスがあったとしても、流石に人件費がかかる以上はお高い代物になるでしょうし。

日本語ウェブコーパス2010→libkkc辞書ネタは一旦ここで区切ります前回書いてはいるものの、CC-100: Monolingual Datasets from Web Crawl Dataに日本語の言語資源(圧縮して15GB、展開後は75GB程度)があるのを見てしまうと、これを利用して辞書を作ったらどうなるかというのが気になっています。簡単に見たところではテキストの抽出は済んでいる状態なので、あとはnwc-toolkitにあるツールのうちUnicodeの正規化及びN-gramコーパスの作成辺りを使えばイケるのではないかと考えているところです。そんな理由でnwc2010-libkkcのMeCab対応をやっていましたという訳で。

日本語の言語資源を日本人が自由に手に入れることができず、外国経由で入手しなければならないこの状況を、「日の丸○○」至上主義な人達はどう考えているか、是非とも聞いてみたいものですが…状況が分かっていないのか、分かっていても無視しているのか。55.6kg(21:50)

17-Sep-2023
[頻度がキーポイントという気はするけど]

日本語ウェブコーパス2010のN-gramコーパス(形態素N-gram)、頻度1000以上だけでなく頻度100のデータからもdata.arpaを作成しlibkkcの辞書として使用可能なことを確認しました。とはいえ、fcitx5が660Mbyte近くのメモリを消費するのでこれはちょっとやりすぎな気がします。

どの程度の頻度であれば適当かを知るべく、nwc2010-libkkcで頻度をあれこれ変えて生成したdata.arpaの先頭に記される1〜3-gramのエントリ数を調べてみました。生のデータはこんな感じになるのですが、グラフにした方が分かりやすそうなのでgnuplotで描いてみました(何年ぶりにこれ使ったんだろう)。左から1-gram, 2-gram, 3-gramとなっていて、横軸は頻度、縦軸はエントリ数となっています。

t1.png t2.png t3.png

1-gramのグラフについては原点が(0,0)ではないので注意が必要です。(情けないことに高等数学を忘れてしまっていて…きちんと計算して値を求めることができないのでグラフから雑に読み取ってしまいますけど)なんとなく頻度500辺りで辞書を作るのが良さそうに見えます。

日本語ウェブコーパス2010→libkkc辞書ネタは一旦ここで区切ります。改善すべき点はありますし、この方法で辞書を生成するのは限界があることも分かっていますが、とりあえず使えそうな辞書を手軽に作るならこれで十分でしょう。後は然るべき方にお任せします。55.7kg(21:40)

23-Sep-2023補足:このグラフ、どうもジップの法則(Zipf's law)なるものと関連があるようですね。両対数スケールでグラフを描いた方が良かったのかもしれません。

16-Sep-2023
[どうにか…?]

結局libkkc-dataのsortlm.pyにこんな感じの修正を入れることで日本語ウェブコーパス2010から生成した辞書データをlibkkcで利用することができるようになりました。Emacsでの文字入力は日頃は(Ctrl-oで切り替えて)Anthyを使っているものの、今回はテスト用に(Shift-spaceで)libkkc越しに入力しています。とはいえ、OpenBSD上の設定はSKK辞書ありにしているため、そちらの支援がかなり効いているんじゃないかという気もします。ここまで打った感じではそんなに悪い感じはしないんですけどね。

日本語ウェブコーパス2010からdata.arpaを生成するための支援ツールはGitHubに上げています(ここで、あげて→上て、としか変換できずに詰まりました…そして詰まりも、詰りしか変換できず「ん?」となりました)。README.mdは完全に愚痴モード入っていますが、実際由々しき問題なのは確かなのでこれは誰かがどうにかしていくしかないと思います、後ろ盾のない何処の馬の骨とも知れぬ個人の道楽ではなく(後ろ盾が変換できなかった)相応の富と権力・(「てん」ではなく「なかてん」でないと出ません)名声のある人じゃないとできないお仕事のはず。

…とはいえ、libkkcが世に出てから相当の時間が経過している以上、辞書データの素となるdata.arpaの生成方法を自分知らないだけで、実は結構知られていたりすることなのかもしれません。なのでまあこんな風に「やったぜ俺はー」なんてことを書くこと自体、実はかなりイタい人に見えている可能性も否定はできません(むしろその可能性は高いでしょう)。既に実現できているというならきちんと公開してくれりゃあこっちも余計な時間使わずに済んだのによ💢、とは書いておきます。

忘れる前にメモをしておきますが、どうも(libkkc-dataの)data.arpaにはこういう性格があるようです。

  1. 1-gramを単語の一覧とする
  2. 2-gramは1-gramで定義された単語のペアである
  3. 3-gramは2-gramで定義された単語のペア+1-gramで定義された単語である
  4. 1-gramはBOS(<s>)およびEOS(</s>)のエントリを含む

1.〜3.についてはsortlm.pyの対応でどうにかなりました(→余計なエントリがあるとクラッシュする問題があったのでそれは解決しました)が、4.についてはlibkkc側がどうしても必要としている以上それ以外で頑張るしかありません。data.arpaにBOS/EOSを含んでいない場合はsortlm.py側で適当に補う方法で誤魔化してみましたが、適当な補完でどの程度使い物になるかは現時点ではよく分かりません。なにしろここまで文章を打ち込むこと自体が初めてなものなので。

最初に書いたように、日記の記述はAnthyを使っているのでlibkkcではない…なので辞書をすげ変えたところで(挿げ替える、は出なかった)どの程度癖が変化したかは評価できないのが正直なところです。一つ分かったことは、品詞だのなんだのといった細かいことを考えなくても、統計的な手段だけでまあまあ使えるかな漢字変換辞書が手に入るのかなあという期待とか可能性とかそんな感じのもの、です(実際は形態素解析を通しているので、裏では細かいことがあれやこれやと動いています)。

ところで、EmacsからCtrl-oで直接libkkcを呼べるような手段が欲しいんですがどこかにありませんかね…?56.4kg(22:15)

11-Sep-2023
[むーん…]

Google Web N-GramをSRILMでARPA化できませんか?の問いに対してそれはMSRLMかIRSTLMでやることですという返信があった以上、SRILM以外の手段を使うべきなのでしょう。という訳で、MSRLMも今なおダウンロード可能な状態にあるようですがここではIRSTLMを使います。Debianならapt-get install irstlmでインストールできるので楽です(/usr/bin/irstlmの他、/usr/lib/irstlm/binに各種実行バイナリが格納されます)。

あとはA tutorial on the IRSTLM libraryのHow to to distributed LM training: step 4, 5, Further steps for LM trainingにあるように、

という手順で生成できています。作成に使用したツール類と得られたdata.arpa(ストレージの都合上圧縮しています)を置いときます。

流石に07-Sep-2023のようないい加減にでっち上げたdata.arpaではなく、言語モデルを作成するツールできちんと作ったdata.arpaなので今度はlibkkc-dataのsortlm.pyも文句を言わないだろうと思っていたのですが…相変わらず、IndexError: tuple index out of rangeを起こして先へ進めません。sortlm.pyに問題があるとか……?55.5kg(22:55)

10-Sep-2023
[…こうかな?]

相変わらず日本語ウェブコーパス2010のN-gramコーパスをどうやってSRILMに食わせるのかと足掻いているのですが…FAQのB6、ngram(1)make-google-ngrams.gawkWeb日本語Nグラム第1版のREADMEの四つに答えは書いてありました。

N-gramコーパスを収めるディレクトリをoutputとすると、こんな感じのディレクトリ構造になります。頻度1000以上では各N-gramに対し1つのファイルしかありませんが、それより少ない頻度の物になると複数のファイルに分割されるはずです。圧縮の有無は問わないようなので、とりえず無圧縮にしています。

output
|-- 1gms
|   `-- vocab
|-- 2gms
|   |-- 2gm-0000
|   `-- 2gm.idx
`-- 3gms
    |-- 3gm-0000
    `-- 3gm.idx
    

1gms/vocabは「単語(タブ文字)出現数」が列挙されたファイルで、分割されていないことを除けば1-gramの内容と同じです。また、SRILM-FAQのB6にあるLMパラメータ(google.countlm.0)で指定するvocabsizeは単語数(vocabの行数)、totalcountは単語の総出現数(出現数の総和)になります。頻度1000以上であっても、64bit幅でないと総和が正しく出せないので注意が必要です。

2-gram以降のデータについては分割することが認められていますが、Ngm-KKKK(NはN-gramの次数、KKKKは0〜の連番+0 paddingして4桁にする)というファイル名である必要があります。また、一つのファイルに格納できるのは10,000,000エントリが上限となるため、どのように分割したかをNgm.idxに記す必要があります。

Ngm.idxの書き方についてはmake-google-ngrams.gawkに書いてありますが、たとえば3gm-0000の最初のエントリが「<S> ぁ の(タブ文字)3217」だとすると、3gm.idxは「3gm-0000(タブ文字)<S> ぁ の」となります。複数のNgm-KKKKが存在する場合、それについてもNgm.idxに記していく必要があります。

この辺りの話、先に挙げた四つの資料をきちんと読んでいたり、DVD-Rを買った人なら知っていて当然なのでしょうが、ロクに資料も読まずに足掻いたのでこの体たらくです。

チューニング用の文書は何を用意すれば良いか分からないのでngram-count -text tune.text -write-vocab tune.vocabの手順は飛ばしますが、FAQにあるようにgoogle.aliasesと仮のgoogle.countlm.0を作成し、ngram-count -debug 1 -order 3 -count-lm -vocab-aliases google.aliases -limit-vocab -init-lm google.coutlm.0 -em-iters 100 -lm google.countlmでgoogle.countlmが得られるところまでは来ています。

問題は、これをどうやって.arpa化するかなんですが…どうやるんですかね?55.6kg(20:30)

07-Sep-2023
[libkkc-dataの]

libkkcの辞書データたるlibkkc-data、これに含まれているdata.arpaとはなんぞ…と調べていたのですが、生成するのはなかなか難しそうですね。(SSL鍵の有効期限が切れているようですが)Next Generation Input Methods(PDF)を見るに、

libkkc.png

Wikipedia日本語版から得た十万文とYahoo!知恵袋から得た二万文を用いて、3-gramの言語モデルを生成したとあります。data.arpaのデータフォーマットはngram-format(5)に従ったものですので、SRILM等のツールを使ったのではないかと思われます。また、単語の区切りが明確である英語と異なり、日本語の場合は形態素解析を行いさらに(かな漢字変換用の辞書である以上)読み仮名を振らないといけないのですがこれはおそらくMeCabか何かを使っているのでしょう。

…と、辞書を生成する際に使用する3-gramデータ(data.arpa)の生成方法について予想してみたのですが、こうやって作りましたという具体的な手順について探してはみたもののどこにも見当たりません。libkkc-data付属のドキュメントも見ていますが、インストール手順しか記されていません。

おそらく今data.arpaを構築するのであれば、日本語ウェブコーパス2010にあるテキストアーカイブからMeCabを用いてコーパスおよび読み仮名の付加を行い、そこからN-gramを生成するといった手順になるかと思われます。テキストアーカイブを展開すると396GB、形態素解析結果が4.36TBとあるので、2010年頃よりも容易に手を出せる規模…とはいえ、この目的のためだけにストレージを用意する余裕は当方にはありません。

日本語ウェブコーパス2010ではN-gramコーパスも用意されており、ここからarpa形式のデータを作ってみる手もありそうです。実は試しているところなのですが、手法が雑すぎるのか(※)libkkc-dataのsortlm.pyがエラーを出してしまい、辞書の生成までは至っていません。

(※)振り仮名はkakasiに用意してもらい、kakasiとやりとりするために内部ではUTF-8→EUC→UTF-8変換を行っている(読み仮名を付けられない物は変換対象から外す)。候補の出現率は、(候補の出現数)÷(各N-gramにおける候補の出現数の総和)とし、スムージング処理は行わない。バックオフ係数はとりあえずlog100.85を設定しているが、これはdata.arpaがそのくらいの値を設定していることが多いといういい加減な理由によるものであり、明確な根拠はない。

class DecoderToolからユーザ辞書を呼び出せない以上はシステム辞書(data.arpa)の充実は必須ですし、ソフトウェアを使い続ける上ではシステムの要となるデータの作り方を確立しておくことも重要であると考えています。たとえ、N-gramが今となっては古い言語モデルになったとしても。55.9kg(22:40)

08-Sep-2023補足:日本語ウェブコーパス2010・N-gramコーパスの書式の項には「Google N-gram コーパスと同様に,Ngms/Ngm-KKKK.xz というファイルに 1000 万 N-gram ずつ格納しています.」と記述があり、またSRILM-FAQの「B6) How can I use the Google Web N-gram corpus to build an LM?」の項にGoogle N-gramコーパスをSRILMで使う方法が記されています。下手な変換を行うよりもSRILMを通す方がはるかに良さそうなものの、google.countlm.0を作成する際に必要となるvocabsize(1gms/vocab.gz), totalcount(1gms/total)が日本語ウェブコーパスには含まれていません。なので、直接変換を試みた訳なのですが…結果は御覧の通り。

Google形式(と仮の名前を付けておく)のN-gramコーパスのフォーマットについては、SRILMのソースコードに含まれるmake-google-ngrams.gawkを見れば良さそうですが、vocab.gzはともかくtotalについての説明はありません。Web日本語Nグラム第1版のREADMEについても似たようなものです。これを調べるために言語資源協会に\44000払うのは流石に無理です。

Google Books Ngram Viewer Exportsに日本語があればそれも参考になるのでしょうが、無いんですよね…(英・中・仏・独・希・伊・露・西に対応しています)。

02-Sep-2023
[drowe67/LPCNetのOpenCL対応化実験で気づいたことですが]

以前作成したvec_sse.h、これ要らないです。元々vec_avx.hにSSE(4.1)対応が仕込まれており、こちらを使った方がvec_sse.hを使うよりも速いことが分かりました。という訳で削除要請出して無事に受理されたので、この件はおしまい。

なお、lpcnet_decでのデコード結果を比較するに、vec_sse.hを使った場合はベクタ演算を使わなかった場合(vec.h)の動作と同じ結果になり、vec_avx.hによるSSE/AVX対応を行った場合はこれと異なる結果になります。xiph/LPCNetと異なり、sgemv_accum8x4(), sparse_sgemv_accum8x4()は使っていないのでこの部分の(qweightがfloatではなくsigned charになっている)影響ではなさそうですが。

ていうか、最初っから対応してたんならPR投げたときに教えてくださいよ誰か…

折角なので、25-Apr-2020の方法で取ったベンチマークの結果を出しておきますね(どちらもDebian-12/x86_64上での実行結果です)。

Intel Core i7-7700/AVX
7.132s
Intel Core i7-7700/SSE4.1
8.941s
AMD A8-7600/AVX
15.146s
AMD A8-7600/SSE4.1
16.453s

SSE4.1使用時の性能劣化がそれほどひどくないのを見るに、SSE4.1向けのビルドでも問題無いような気がします。x86_64では問題なく、i686ではボロボロという可能性もありそうですが。55.6kg(22:20)

03-Sep-2023補足:ついでにこちらも。i3-13100はWSL2上のUbuntu 22.04.3 LTS、i7-7700(32bit)はQEMU/kvm上のSlackware-15.0で試しています。

Intel Core i3-13100/AVX
3.730s
Intel Core i3-13100/SSE4.1
4.870s
Intel Core i7-7700/AVX (32bit)
illegal instructionによりテスト不可(仮想マシンがAVX非対応)
Intel Core i7-7700/SSE4.1 (32bit) -msse4.1のみ
29.428s
Intel Core i7-7700/SSE4.1 (32bit) -msse4.1 -mfpmath=387
29.465s
Intel Core i7-7700/SSE4.1 (32bit) -msse4.1 -mfpmath=sse
29.298s
Intel Core i7-7700/SSE4.1 (32bit) -msse4.1 -mfpmath=387 -ffast-math -DFLOAT_APPROX
29.812s
Intel Core i7-7700/SSE4.1 (32bit) -msse4.1 -mfpmath=sse -ffast-math -DFLOAT_APPROX
29.914s

うーん、足掻いてはみましたが…32bit(i686)はAVX必須、は揺らがないようです。

01-Sep-2023
[オギノパン近くの(3)]

28-May-2023の続き。ここしばらく行けていなかったので、時間を作って見てきました。東海鳥屋線だそうです。東海小倉線と対(?)を為す名付けですね。

timg_20230901_081826_795.jpg timg_20230901_081905_219.jpg

timg_20230901_082445_479.jpg timg_20230901_082254_951.jpg timg_20230901_082314_272.jpg

6月25日の時点で名称が判明している→6月のどこかの時点で標識が取り付けられた、ということになるのでしょうか。この時期は異動やマシンの組み換えでバタバタしており鉄塔巡りどころじゃなかったんですよねえ。

異動に関してはその後色々ありましてと適当に濁しておきますが、今月で転職してから10年が経過して、結婚してから20年が経過していたりします…信じられないことに。55.9kg(21:40)