日本語文章を「Neural Network Console」で学習・評価可能なように「'0000'から'FFFF'」のコードの出現頻度を使って符号化する前処理がテーマです。
前提
日本語文章を「Neural Network Console」で学習・評価可能なように、列固定の数値データに変換するテーマでは一度記事を書いてます。
上記記事では、'00'から'FF'の256列のコードの出現頻度で数値化してます。
ただ、この時の256列というのは、これがベストだから・・という理由ではなく、EXCELのグラフで生成したデータを目視確認したり、処理時間を短くするなどの諸々の妥協の産物でデータを大きくしないようにしただけです。
なので。
日本語のようなマルチバイト文字を、シングルバイトで処理するのは、少々無理があるのでは?というご指摘の声については「まったく、その通りですが・・うんぬん」と言い訳をし続けることになってます。
でも、よく考えてみれば。
マルチバイト('0000'から'FFFF'の65536列)でやった方が本当にベストに近づくのか?というのは試してないわけです。
Pythonのクラスを'0000'~’FFFF'のマルチバイト対応に変更
ベースは上記の記事のクラスです。
それを、マルチバイト('0000'から'FFFF'の65536列)に変更します。
変更する部分は2か所。
- 初期化する部分を、'00'~'FF'ではなく、'0000'~'FFFF'にする
- 文章を文字コードに変換する部分をマルチバイト対応にする
初期化する部分を、'00'~'FF'ではなく、'0000'~'FFFF'にする
これはシンプルに'0'~'F'を4列つなぎ合わせて行けばいいですね。
# 初期化 0000からFFFFをひとつずつおく。位置を固定し、かつ、0エラーを回避する l_line = [] l_seed = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'] for i1 in range(16): for i2 in range(16): for i3 in range(16): for i4 in range(16): l_line.append(l_seed[i1] + l_seed[i2] + l_seed[i3] + l_seed[i4])
文章を文字コードに変換する部分をマルチバイト対応にする
こっちは単に取得する範囲を広げるだけ。
なのですが、1バイト文字の時は'00'を前につけるなどの工夫がいります。
ちなみに、[2:6]のようにスライスしているのは、16進数に変換した文字列には不要な「0x」という文字列が頭についている(0x0D0Fみたいに)ので、それを除去しています。
for i,l_pt in enumerate(l_text): # 不要な空白などを除去 l_p = re.sub(self.__sub_pat,"",l_pt) # 空行は無視する if l_p: # 元テキストも出力しておく tout_f.write(l_p + "\r\n") # 1行分の単語を分割 o_malist = o_t.tokenize(l_p) for n in o_malist: # 記号以外を対象にする if not (o_reg.match(n.part_of_speech)): # 分割した単語を1行分リストに加えていく for i in range(len(n.surface)): h = str(hex(ord(n.surface[i]))).upper() if(len(h) ==4): l01 = '00' + h[2:4] l_line.append(l01) if(len(h) >=6): l02 = h[2:6] l_line.append(l02)
他の部分はそのまま使えます。
同じニュースコーパスを処理してみる
上記の部分だけを修正して、マルチバイト('0000'~'FFFF')の出現頻度でカウントする方法でNNC用データを作り直しました。
65536列のデータになります。
ニュースコーパスを加工してみた
元にしたテキストデータは、「使い方30」と同じく以下の記事で紹介している「livedoorのニュースコーパス」です。
256列版と異なり、データ作成にも相当(自分の古いPCだと1時間近く)かかります。
しかも、できあがったデータをチェックしてみたら、ほとんどがカウント1の同じデータという実に筋の良くないデータになってました。
実世界で例えるなら・・観客が1000人位しか入ってない東京ドームの観客席・・みたいにスカスカです。
たぶん、マルチバイトにするには、記事データが小さすぎるのですね。
うーーん。
嫌な予感を感じます。
でも、せっかく作ったので学習と評価をやってみます。
比較用に、同じネットワークモデルで学習・評価する
'00'~'FF'でやった時との比較をしたいので、同じネットワークモデルを使います。
変更点は、inputのサイズだけです。
前回は「1,256」ですけど、今回は「1,65536」です。
そのため、続くAffineのOUTPUTサイズもちょっと変更してます。
それ以外は一切触らずに学習をしました。
学習の時間は画像なみにかかるし結果グラフも不安な感じ
256列('00'~'FF')の時は、学習はものの数分で終わってました。
しかし、さすがに65536列になると・・・時間がかかります。
自分のCPUのみの環境だと、ざっと2時間位ですかね、
相当、精度があがってくれないと元はとれない位の差があります。
学習結果のグラフはこんな感じです。
なんじゃ?これは。
TrainingでもValidationでも、ボコッと大量にエラーがでたりでなかったり、ミニバッチ単位で結果のバラつきがひどすぎる感じがあります。
うーーーん。
ますます、不安がつのります。
これは期待できないかも・・・。
そう思いながら、評価を実行してみました。
評価結果は無茶苦茶改善されたんだな・・これが
評価の結果は以下の通りです。
99.76%!
どうなってんの?というような数字です。
学習結果を見た時の予想に反して、256列('00'~'FF')パターン時から、約2%近く改善しています。
それにしても、この改善率はすさまじいですね。
まとめ:まあ、使えそうな気はする
正直、過学習じゃないかと思って、データを見直しました。
異常はないです。
念のため、他のニュースのテキストを持ってきてバリデーションデータを差し替えてみても、ちゃんと精度がでています。
過学習ではないですね。
なんなんでしょうね。
一体。
正直、データの感じからして、もっと長いテキスト(小説とか)だと、こういう結果になりそうな気はしてました。
でも、今回のこの結果は予想してませんでした(笑)
でも・・まあ。
マルチバイト版('0000'~'FFFF')のアプローチは、データ作成にも学習にも時間はかかるけど、それに見合う位の精度向上の可能性は持ってる。
そう考えても・・いいのかな?