ラベル CEDEC の投稿を表示しています。 すべての投稿を表示
ラベル CEDEC の投稿を表示しています。 すべての投稿を表示

2022年9月7日水曜日

CEDEC でやってた補助動詞の漢字・ら抜き言葉の検出を実装してみた

CEDEC 2022 の「AIによる自然言語処理を活用したゲームシナリオの誤字検出への取り組み」で誤字検出方法が解説されてました。
セッションタイトルにある AI の部分は BERT 使った誤字検出の話で、サクッと実装は難しそうなので、比較的簡単そうな「補助動詞の漢字」「ら抜き言葉」の検出を実装しました。

実はこのセッションは昨年の CEDEC 2021 の続編で、昨年の内容も一部検証実装してました。
そのときの記事はこちらです。
CEDEC でやってた表記ゆれ検出をお試し実装してみた

今回の実装は昨年書いた tails-of-words に機能追加として実装してます。
なんですが、昨年のアップデートかつ実装難度としても高くないのであまりここに書くことがありません。。
(どういうロジックなのかは割とまんまな記事が出るのでそちらか、おそらく CEDiL に資料公開されると思うのでそちらを見て下さい。)

ら抜き言葉検出の改良

強いて書くとすると「ら抜き言葉」の検出がセッションのとは少し異なるくらいですね。
セッションでは「ら抜き言葉」の誤検出の例として以下のテキストがでてました。

  • 写真撮ってきたから見れ!
  • あれ?あれれれ?
  • 今こそ来たれ!
まず資料の通りに実装した場合の結果がこちら
なぜか1つ目と2つ目は「ら抜き言葉」とは判定されない解析結果でした(つまり誤検出しない)。
ツイートでは前処理の違いかもと言ってますが、 jumanpp に渡す前にテキストの正規化をしているのでもしかしてその違いがあるのかも?と思ったのですが、前処理で変化するような入力テキストではないので違いました。
使っている jumanpp or 辞書の違いでしょうか。(確認できないので、深追いはしない)

では、「今こそ来たれ!」ですが「れ」の直後の品詞が「特殊」となってます。
セッションで誤検出の例として上がったものすべて「特殊」品詞が直後にあるので、このパターンを「ら抜き言葉」から除外すれば良さそうです。

というわけで改良後はこうなります。

最後に
BERT とかそのへんもいつか触ってみたいです。
では。


2021年9月8日水曜日

CEDEC でやってた表記ゆれ検出をお試し実装してみた

CEDEC2021: ゲーム制作効率化のためのAIによる画像認識・自然言語処理への取り組み
ゲーム制作効率化のためのAIによる画像認識・自然言語処理への取り組み - Speaker Deck

こちらの講演の中であった表記ゆれ検出の実装実験をしてみました。
ポイントとなるのは「形態素解析」と「編集距離」です。

形態素解析はこのブログでもたまに扱ってました。
ブログズミ: TreeTagger を使ってソースコード中の単語をリストアップしてみた
ブログズミ: ソースコード中の単語からの略語/スペルミス検出に挑戦

↑これらは TreeTagger 使ったものでした。

実は、前職でも同じような表記ゆれ検出はしたことがあって、そのときは MeCab で形態素解析し、単語の出現数をカウントしてソート出力するだけのものでした。
出現数の少ない単語から見ていくと、「あ、これは揺れてそう」ってのがわかったのでそれなりに有用でした。
なので、CEDEC の方法であった「出現数の差が大きいほどスコアが上がる」は良いと思いました。

で、今回は形態素解析には Jumanpp を編集距離はレーベンシュタイン距離を使いました。
実装はこちら。
講演の内容そのものの実装ではないです。スコア計算の部分はテスト対象の入力に合わせて書いたので万能ではないと思いますが、なるべく一般化したルールにしてるつもり。

https://github.com/srz-zumix/tails-of-words

PyPI でも公開してるので pip でインストールできます。
https://pypi.org/project/tails-of-words/0.1.2/
また Dockerhub にイメージもおいてるのでそれ使っても実行できます。
https://hub.docker.com/r/srzzumix/tails-of-words

実装メモ

実装上のポイントをメモしてます。

  • yomi がひらがなの場合とカタカナの場合がある
  • yomi に長音(ー)が追加される場合がある
  • 総当りで調べるのですべての単語差分を記録すると killed される
  • 半角スペース、"、@、# を含んでると pknp で例外出るので全角にする
  • 「えー!?」のように全角!・?があると、つながった状態で1単語になるので、分解するため半角にする

テスト

試しに拙著をチェックしてみました。

拙著の場合、未定義語(15)まで集計対象にするとアルファベットのみの単語の大文字・小文字違いがスコアが高くなり、ノイズだったので -i 6 で名詞のみに制限。
-t 1 で 1.0 以上のスコアのものを表示してます。

画像をご覧いただくと、「コンパイラー vs コンパイラ」の表記ゆれを検出してるのが見つかります。それ以外は表記ゆれではないと思いますが、書き損じの可能性はあるかもしれませんね。

最後に

実装自体は1日、スコア計算の部分とかの調整で1日。
あとは周辺機能の整理とかで1日くらいですかね。
(仕事じゃなくて夜中に書いてたやつなので工数じゃないよ)

とりあえず最低限のものを作るだけなら、めちゃくちゃ簡単にできます。
ただし、精度はいまいちだと思います。
リストアップされたものを人間がチェックする必要性がありますが、リストアップする部分まで人間がやるよりはかなりマシでしょう。

ここから検出精度を上げるのはとても大変だと思います。
トライアンドエラーで色々評価軸を追加したり、スコア計算の調整したりすることになると思いますが、コスパがどんどん悪くなっていくと思います。
(業務外だったら関係ないのかもしれないけど・・)
流行りの機械学習で精度アップできるかもしれないですが、どうなんでしょうね?
(この辺は詳しくないのでわかりません)

実はこの手の話をすると、似たようなこと昔やったことあるって人が結構います。
みんなサクッと実装できたといいますが、精度・コスパの話も同じような感想でした。

これは完全な余談なんですが、
Jumanpp の出力をいい感じに print したいなーと思って Power-Assert みたいな出力にしようと(すぐ道草をする悪い癖が出そうになったのを我慢)して、適当に作った print が割といい感じにできたのが良かった :D


対して難しいことはしてませんが、この実装が役に立てば幸いです。
では。

2019年9月13日金曜日

[CEDEC2019][感想] LUMINOUS ENGINE のログ分析と自動テストで提案されたリプレイ的自動プレイ手法について

一応仕事で行っているので、個人のブログにこういったことを書くのはほとんどしないのだが、
個人的に手詰まりを感じていた分野に対して、非常に興味深い手法が提示されたことと、どこかが実現してくれないかなーという気持ちを込めて、ブログに書き起こすことにした。


セッションについて
まずは、当該セッションについて簡単に説明をしておくが、
大規模開発のためのLUMINOUS ENGINE のログ分析と自動テスト
こちらのセッションではいくつかのトピックが出ていて、AI の詳しいことはさっぱりわからんので、このブログで書きたいことと関係のある部分だけ、かいつまんで書きます。
(詳細は資料(CEDiL)または今ならタイムシフトを見て下さいmm)

ズレを許容するリプレイ的自動プレイ
自動リプレイの実現方法としては、大きく分けて2つに分類できる。

* パッド入力を記録
* スクリプトで制御

パッド入力を記録する方式は、ゲーム非依存で録画したものを再生するだけで実現が可能。ただし、ゲームに依存しないのでゲーム特有の状態変化に弱い(乱数・FPS・演算誤差とか)
スクリプトで制御する方式は、ゲームに特化した制御ができるのでなんとでもなる。ただし、パッド入力方式ほどの手軽さがない。

セッションでは、パッド入力方式を軸に
リプレイがずれないように、がんばるのではなく、
一度ずれても、復帰できるように
がんばった方が、よさそう。
という考えから、マシンラーニングによるラーニングリプレイを実装されていました。(スゴイ)



個人的に、ゲームに依存してはいけない(できない)絶対条件でリプレイ方法を考えていたので、
この方式はすごく参考になった。

ゲームの情報に依存しない
個人的に素晴らしいなと思ったのは、ゲームにおける意味のある情報を要求しないでも実現できているところ。
入力に使われる値は、ゲーム内の意味のある情報ではありますが、AI はそれを認識しておらず、単なるデータ配列として扱っています。
出力は「キーパッドの入力」であるため、こちらもゲームの内容には一切関わらないものです。

セッションでは、リプレイの撮り直しもマシンラーニングで行っていました。(スゴイ)
ただ、こちらはゲームおける特定の状態が認識できた方が、よい結果が得られるようで、セッションでは壁との衝突を認識させていました。
ここで、ゲームから壁に当たったよーという情報をもらうことなく、入力はあくまでデータ配列のまま解決していたのが素晴らしいと思いました。


これをそのまんま使いたい
たぶん、このセッションを聞いた方の多くがこう感じたのではないか?と思うのですが、私もその一人です。
システムとしてはゲームに依存しないので、このシステムは切り売りできるのでは?
(ゲームジャンルには依存するかもしれないが、考え方としては流用できるのでは?)

と、思ったところで1つの案を思いつきました。
ハードウェアでできるんじゃない?

開発ツールがリプレイ的自動プレイをできるようになる?
単純に時間とパッド入力の録画を再生する機能(パッドリプレイ)は実は存在しますが・・
これは当該セッションや他の自動プレイ関係のセッションでも語られてますが、しょーじき全然再現できないです。
(乱数シードの固定はもちろんしてても、どうしてもずれちゃう)

なんらかの同期信号も録画して、ゲーム内のループと同期しながら再生したらいいんじゃない?とか考えたりもしてましたが、
バグの再現方法としてのパッドリプレイをゴールにしてたので完全再現という呪縛から逃れられず、考えが凝り固まってましたね。。
なので、(開発ツールでやるなら、ここどうするの?ってところはありますが)ラーニングリプレイはなんか良さそうだなと思いました。





LUMINOUS ENGINE のリプレイ手法は、メモリ上の任意の値を入力に、パッド入力を出力するものでした。
開発ツールであれば、メモリ上の値はいくらでも見ることができますし、パッド入力などデバイス入力の状態も取得できます。
ログとして値の変化をためていく部分もハードウェアで処理させるほうが有利ですし、GAME への影響もありません。

メモリ上の任意のアドレスをどう示すかは、デバッグシンボルとなんらかのマーカーをおけばなんとかなりそう。
ゲーム機の Vsync は取れるが、ゲームループは単純には取れないので、これも上の方法で取得。
「取り扱い注意な値」は、デバッグ情報あればなんとかなるんじゃないかな。

出力として得られたパッド入力は、当然開発ツールから流し込めますし、わりと現実的なのでは?と思ってしまいました。。。
(テキトーに殴り書いてます・・)
(あ、リプレイの撮り直しは構想から除外してます)


ここでポイントになってくるのが、「ズレの許容」と「ゲームの情報に非依存」であるところです。
「ズレの許容」は単純なパッドリプレイの弱点を克服し、「ゲームの情報に非依存」であることで汎用的なツールやゲーム開発者が誰しも使う開発ツールにも適用できる。はず。

ぜひ、将来の開発機材には標準で搭載されていて欲しい。


最後に
勢いでここまで書いたが、まぁだからなんだという内容だ・・
他力本願です。って言ってるだけなんだが、まぁなんだ気持ち伝われ。
(そういうのまたやってみたいという気持ちはあるよ)

では。

2019年9月4日水曜日

[CEDEC 2019] 行ってくる

今日から CEDEC 2019 ですね。
私はいつもの CI love T シャツで参加します!



では。会場で!!