pkeを使い日本語のキーフレーズ抽出を行う

Python Keyphrase extraction (pke) というモジュールがあります。TextRank等著名なキーフレーズ抽出手法をサポートしているPython用パッケージです。 GiNZAの登場により、内部でspacyを使っているソフトウェアが日本語でも使えるようになったケースが増えてきているのですが、pkeも最近の更新で完全に無改造で日本語を扱えるようになりました。 それ以前にpkeを日本語で使うための記事がいくつかあります。 はじめての自然言語処理 第5回 pke によるキーフレーズ抽出 2021年版PKEライブラリーによる日本語キーフレーズ処理のサンプル・PKEをアップデートしたら動かなくなってしまった方へ pkeはここのところ頻繁に更新があり、ストップワード以外は無改造で動くようになっていました。ストップワードに関しても先の記事のようなハックをしないで済むようなPRを出したところ、もうちょっと洗練されたコードに置き換わってくれました。ともあれ上記の記事の方法と使い方がちょっと変わってしまったのでここに記録しておきます。サンプルはオージス総研の記事に倣います。 language=’ja’とした場合、spacyの利用可能なモデルから’ja’で始まる最初のモデルを利用します。したがって、ginzaが入っていればja_ginzaモデルが自動的に利用されます。

テキスト分類をDNNでやってみて思うところ

以前このような記事を書きました。 Recurrent Convolutional Neural Networks for Text Classificationを実装した  複数の単語から構成される文章を、Bag-of-Wordsと対応する単語分散ベクトルで表現し、特徴ベクトルの最大値のみを抽出する、という感じの手法です。 これの実装を書いた時はまだあんまり機械学習のことがよくわかっていなく(今もよくわかっていませんが)、それでも実験的、感覚的に「この手法は特に単語が増えると精度でないだろうな」と思っていました。 なので、その後畳み込みネットワークベースの手法を試しています。他の人が書いたChainer実装は既にあったので、自分はそれの最上層をSPP-Netに置き換えただけのものを試しています。 ichiroex/chainer-cnn: convolutional neural network for sentence classification by Chainer (オリジナル実装) https://github.com/knok/chainer-cnn (そのfork) 畳み込み(CNN)とSpatial Pyramid Pooling(SPP-net)を使ってテキスト分類 – Qiita (解説記事) 基本的に、こちらのほうが特徴量をより多く捉えているはず(層の数とか種類とかから類推)なので、きっと性能は高いと思います(未検証)。そこは同じテータセットを使ってちゃんと試したいところですが、GPUの空き時間ができたらということで… そんなわけでRecurrent CNN(RCNNはRegions with CNNと混同しやすい略称なのでこう記述します)は「自分も論文だけ見て実装することはできたので満足。だけど手法としてはいまいちっぽいよね」という気分でいました。 ふと先日この記事が目に飛び込んできました。 AIで2chに悪口書いてる人を特定してみた。 – ちょいちょいブログ ちょっと過大に扱われてしまったのではないかと思い、この記事を書いています。 分類結果の出力 自分の実装では評価時に最終出力として、全層結合層(Fully Connection layer)の値を生のまま出しています。実際にはこれにソフトマックス関数をかませて0〜1の確率値に整えるべきなのですが、そこをちょっとさぼっています。 ともかく、ソフトマックス関数で計算される分類タスクの出力は、全ラベルそれぞれの確率の合計が1になるよう調整されます。 Recurrent CNNでは分散表現の実数をそのまま加算するため、全体としては大きな値になりがちでです。その辺りの正規化が皆無なので、おそらく文章が長くなるほどあやしい挙動を示すでしょう。 分散表現獲得 また、分散表現の獲得もあまりよろしくない作りになっていると思います。乱数を初期値とし、逆誤差伝搬で各文字の分散表現を獲得しています。 十分なデータ量がないと、適切な分散表現は獲得できないと思います。代わりに、例えば一般的な表現が多数出現するデータ量の多いコーパス(Wikipediaの記事、新聞記事など)から、word2vec等で獲得した分散表現を初期値に設定してやる、といったことで性能が向上する可能性があります。 2017/8/30 追記: 今回のケースだとWikipediaよりも2chの各種書き込み、Twitterのツイートから分散表現を事前訓練したほうが良い気がしてきました。 「その他」というラベルの扱いの難しさ MNIST, ImageNet, CIFAR10等誰もが入手できるデータセットは非常に限られた分類のデータしかありません。それらを識別するモデルを用意したとして、まったく関係ないデータを与えると、識別器は無理やり何かしらの値を出力します。運が良ければ何かしらの要素が似ているものへの確率が高く出ますが、最悪まったく関係ないラベルだと推論してしまいます。 これを回避するために、たとえば雑多なデータをたくさん用意して「その他」ラベルを作るという解決方法がありますが、これも一筋縄ではいきません。… Continue reading テキスト分類をDNNでやってみて思うところ

自作辞書のブートストラップを考える

かな漢字変換や形態素解析といった処理を行うにあたって、辞書は必要不可欠な存在です。これを一から自作することを考えています。 適切な単語のリストの作成 単語に対する読み、品詞の追加 単語に対するコスト値の算出 データソースはWikipediaを使う こんな感じでおそらくはできるでしょう。時間はかかると思うので、ゆっくり考えていくつもりです。 今はまず教師なし機械学習による単語分割を使って、単語リストを作ることを試みています。これについては階層Pitman-Yor過程に基づく可変長n-gram言語モデル(VPYLM)の実装が複数あり、それを使うことである程度下処理ができます。 latticelm C++/OpenFSTによる実装 vpylml-python C++/Pythonによる実装 (解説記事) Wikipediaの記事はhttps://dumps.wikimedia.org/jawiki/からダウンロードできます。本文のダンプはjawiki-latest-pages-articles.xml.bz2というファイル名です。これをWikipedia ExtractorというPythonスクリプトでプレーンテキストに変換できます。変換時に警告が出ますが、それはたいてい自己参照に関するものなので、放っておいても大丈夫そうです。 さしあたって、展開ディレクトリ/AA/wiki_00を対象にlatticelmをデフォルトパラメータで実施したところ、以下のような感じになりました。 ちょっと分割されすぎですね…ハイパーパラメータはいろいろとあるので、チューニングはいろいろと必要そうではあります。他に試された人の解説によると、初期状態がすべて分割されている点が大きいとのことです。 以前の記事で紹介した「続・わかりやすいパターン認識 教師なし学習入門」には通常のPitman-Yor過程までは解説されており、VPYMLに関してはなんとなくでしか理解出来ていません。もう少し自分の理解も深めたいところです。 単語分割自体は系列ラベル問題とみなしてRecurrent Neural Networkベースで処理することも出来るそうですが、教師あり学習なのできちんとしたデータセットを作る必要があります。そこにたどり着くまでのところを、教師なし学習との組み合わせでなんとか実現したいところです。

seq2seq用日本語対話データセット生成スクリプト

以前、Instagramの画像から食べ物の画像のデータセットを作成という記事を書きましたが、その中で「次はseq2seq用の対話データセットをどうにかしたい」とこぼしていました。なんとかそれを形にできました。 knok/make-meidai-dialogue: Get Japanese dialogue corpus (github) seq2seqで利用可能な日本語対話データセットをダウンロードするツール (Qiita解説記事) 元データはDFSG準拠のライセンスでない点に注意してください。このツールによって生成したデータも同様の制限を受けます。 画像データセットに関しては複数種類があって、以前作った画像データセットの方にあまり需要はなかったようですが、今回はそれなりに参考にされていそうです。 できればDFSG互換なライセンスで公開できる形のデータセットが作りたいのですが、さすがに対話を一人でやるのはなかなか無理がありそうです。オープンなslackやIRCチャンネルを立てて、そういうデータを作るための雑談をしよう、という提案をしたら参加してくれる人はいますかね…?  

Published
Categorized as NLP

Recurrent Convolutional Neural Networks for Text Classificationを実装した

RNN/LSTMでテキスト分類をしたいと思い、まず自分でネットワーク構造を考えてみました。word embeddingとLSTMを組み合わせて、単純な和を文章全体のベクトルとして扱うことを考えてみたのですが、これは思うように動きませんでした。さっぱり学習する気配がありません。 そこで既に提案されている手法を探してみると、word embeddingの配列をx軸固定の畳み込み演算するという手法がひとつありました(CNNによるテキスト分類)。TensorFlowでの実装もあったのですが、chainerでできないかと思いmax_poolingでstride=(0, 1)といった感じで指定してみたのですが、chainerではstrideの値が0より大きいことを想定しているため0除算が発生して動かせませんでした。 仕方がないので、もうひとつの手法「Recurrent Convolutional Neural Networks for Text Classification」を試してみました(参考: 研究開発:RNNで文書分類(Text Classification) )。 構造としては、いわゆる双方向RNNで単語の出現順、その逆順の2つの方向からRNN(実際にはLSTM)を使って、それらを結合し単語ごとに一つのベクトルを生成します。そして、すべての単語についてベクトル各要素の中の最大の値を取り出したベクトルを生成します。最大プーリングに相当する処理ですが、chainerのmax_pooling_2dは今回の用途には使えませんでした。代わりに、function.maximumが使えたのでそちらを使っています。 結果として、おおよそ望むような挙動を得られました。目視で分類したネガティブな文章とポシティブな文章とを分類することができました。 ソースコードは https://github.com/knok/rcnn-text-classification にあります。Qiitaにも解説記事を書きました(Recurrent Convolutional NNでテキスト分類)。  

自由なデータの重要性

先日、NEologd Casual Talksというイベントに参加してきました。mecab-ipadicに新しいエントリーを追加するmecab-ipadic-neologdに関するイベントでした(Togetterまとめ)。 その中で改めて感じたのは、自由なデータの重要性です。イベントでは「言語資源」という観点でのデータの重要性が語られていました。形態素解析器の辞書として、継続的に更新・リリースがなされているのはNEologd以外ほとんどないという指摘がありました。 自分も2012年にSoftware Freedom Dayの国内イベントで「自由なデータ」という題で発表をしました。 自由なデータ from Takatsugu Nokubi 今になって改めてこの資料を見ると、現在は若干状況が変化している部分もあります。NEologdの出現は、まさしくその一つです。 また、日本語の文章チェッカーとしてtextlintという実装の日本語ルールを作成・公開している人がいます。これまでLanguageToolに若干のルールをコミットしてきましたが、textlintのほうがかなり充実している感じです。 最近は機械学習をやってみたりしているのですが、これもまさにデータの質がかなり重要な領域です。変なデータを元に学習すると、そもそも学習が収束しなかったり、期待しない結果を返すモデルができてしまったりします。この領域でも、チュートリアルに使われる定番のデータセットが公開されています(MNIST, CIFAR-10等)。 最近、自分も画像分類タスクのテストのために作ったデータセットはあるので、なんとか公開できる形にできないかと考えています。実データはInstagramにあるもので、個々の画像のライセンスを確認しないまま集めて分類したのですが、画像URLの一覧という形なら問題なく配布できると思います。オライリー「実践 機械学習システム」でも感情分析用のツイートデータを人力で分類したもののID一覧から実データを取得する、という方法が取られていました。   実際に自分でデータの分類をやってみると、「どこまでをこの分類に含めるべきか」という根源的な問題を実感できます。実際、単純に検索しただけだと「明らかにおかしい」というものから「これはどうなんだろう」というものも出てきます。 この点について、先日の発表の中で印象的だったのが片山さんの「ファッションが大好きなので無限に洋服の文字列データを眺めるのが楽しかった」という部分でした。特定のドメインのテキストでも、きっと同じような感覚があるのだろうとなんとなく感じています。 ともあれ、公開できる形になったら、改めて告知したいと思います。

Debian上でmecab-ipadicをベースに単語を追加する

今時のMeCabには、新しく追加した単語だけコストを計算させる機能があるので、実際に動かしてみました。 参考となるURLはhttps://taku910.github.io/mecab/dic.htmlです。Web上には古いgoogle code上のページがまだ残っており、Googleで検索するとそちらが上位に引っかかるので注意が必要です。 前提として、mecab-utilsとmecab-ipadic(EUC-JP版、UTF-8は不可)がインストールされている必要があります。 次に、登録する単語のエントリーを用意します。諸事情により、EUC-JPで保存しておきます。以下は実際の例です。foo.csvという名前で保存しておきます。 次にモデルファイルを前述のページから取得します。リンク先はGoogle Driveのようです。この記事を書いている2015年10月の時点では、mecab-ipadic-2.7.0-20070801.modelというファイル名になっています。 必要なファイルが集まったら、以下を実行します。 すると、foo2.csvに単語のコストが記録された新しい結果が出力されます。 元のmecab-ipadicのソース(/var/lib/mecab/dic/ipadic/*.csv)とモデルmecab-ipadic-2.7.0-20070801.model)がEUC-JPであるため、新しい辞書の文字コードもEUC-JPに合わせる必要があります。

Published
Categorized as Debian, NLP

gensimのLdaModelバグ

gensimのLdaModelでtop_topic()を使おうとしたらいろいろバグが残っていたので、とりあえず手元で動くようにしてみました。詳細はMLに報告しましたが、これが正しい解法かは自信がありません。 問題は複数ありますが、まずは名前空間に不備があります。”np”と”ifilter”という2つの関数をglobalで利用しようとして失敗します。これは以下のように無理やり定義してやれば問題を回避できます。 これ以外に、LdaModel.top_topics()に与えたcorpusによってはKeyErrorが発生する問題があります。これはMLにも書いたようなパッチで回避できました。 私の環境では、これでgensim 0.11.1においてtop_topicsが機能するようになりました。

Published
Categorized as NLP