漢字の部首を特徴量として用いたCNN+LSTMによる文書分類

漢字の部首を特徴量として用いたCNN+LSTMによる文書分類

こんにちは,Nextremerインターンの杉本です.面白そうな論文を読んだので紹介させていただきます.この論文[1]では,日本語の文章から漢字を構成する部首情報を抽出し,CNNBi-derectional-LSTMを用いて極性判定を行っています.

近年は単語ごとに埋め込み表現を獲得するword2vecやFastTextなどが有名ですが,単語レベル(word-level)でネットワークを学習させる場合,ボキャブラリサイズが大きいためモデルが肥大化し,登場頻度の少ない単語を十分に学習することができません.この解決策(ボキャブラリ削減)として,Byte Pair Encoding(BPE)[2]や,文字レベル(character-level)の埋め込み[3]が提案されています.英語など少数のアルファベットで構成される言語に対しては文字レベルの埋め込みが有効ですが,膨大な種類の漢字を含む日本語や中国語では十分な効果が期待できません.そこで,この論文では日本語でも十分にボキャブラリを削減できる部首レベル(radical-level)での埋め込みを提案しています.結果として,学習するパラメータをword-levelの1/10以下に削減し,さらには既存手法[3] より良い精度でタスクを完了しています.

今回は,この論文について簡単に解説し,性能の検証をしたいと思います.コードはこちらから参照できます.

提案手法

図1. 提案手法のアーキテクチャ
図1. 提案手法のアーキテクチャ

提案手法は図1のようなアーキテクチャをしています.これはcharacter-levelである[3]の手法をraddical-levelへと拡張したモデルとなっています.

日本語の文を入力として,1単語を3文字,1文字を3つの部首として固定長で分解し(4以上は切り捨て),それぞれゼロパディングした後,raddical-levelで \( e \) 次元にEmbeddingしていきます.例えば,物語という単語は図1の中で示すように \( ( e, \ 9) \) 次元の行列で表現されます.ただし,平仮名やアルファベット,記号なども一つの部首と同様に扱われます.radical-levelではボキャブラリを圧縮できるため,低次元のEmbeddingでも問題がないようです.実際,参考論文では15次元でEmbeddingしていました.

Embeddingによって得られた単語の行列ごとにCNN(Convolutional Neural Network) を適用していきます.Convolution層ではウインドウ (\( w_i \)),ストライド (\( r_i \)) がそれぞれ異なる6種類のフィルタを適用します( \( \mathbf{w} = [1, 2, 3, 3, 6, 9], \mathbf{r} = [1, 1, 1, 3, 3, 3] \) ). アウトプットチャネル数はそれぞれ \( 50\times \frac{w_i}{r_i} \)であり,活性化関数はReluを用います.Pooling層では,ウインドウを \( \frac{9 – w_i}{r_i} + 1 \) としてMax Poolingを適用します.その後,各フィルターによる出力を結合し,1単語につき \( \sum_i (50 \times \frac{w_i}{r_i})  \) 次元のベクトルを得ることができます(図2).

図2. CNNでの処理
図2. CNNでの処理

この提案手法では,複数のストライドを適用することで \( r_i = 1\) の時にはradical-levelの特徴を獲得し,\( r_i = 3\) の時にはcharacter-levelの特徴を獲得できるようにしています.得られた単語ベクトルはそれぞれHighway層に通した後,文の先頭の単語から順にBi-directional-LSTM層に入力していきます.

その後,LSTMの各ステップの出力 \( \mathbf{h}_i \) に対してSoft Attention[4]を適用することで,文書ベクトル

\( \mathbf{z} = \sum_{i=1}^l a_i (\mathbf{h_i}) \)

を得ます.ただし, \( a_i \) はタイムステップ \( i \) の additive soft attention であり,以下のように定義されます.

\( a_i = \frac{\mathrm{exp}(\mathbf{u}_i^T \mathbf{u}_a)}{\sum_{i=1}^l \mathrm{exp}(\mathbf{u}_i^T \mathbf{u}_a)} \)

ここで, \( \mathbf{u}_a \) は 各タイムステップの重要性を示す Softmax パラメータであり,\( \mathbf{u}_i \) は \( \mathbf{h}_i \) を入力としたHighway層(活性化関数 tanh)の出力です.上記の処理によって得られた \( \mathbf{z} \) をアフィン変換し,最終的にソフトマックスで出力とします.損失関数はクロスエントロピーを用います.

以上が提案手法のネットワークアーキテクチャとなります.参考論文では,この手法を極性判定のタスクに用いることでAccuracy=0.936を達成しています.

評価

それでは,実際に提案手法を評価してみましょう.参考論文の内容をもとにChainerを用いてコードを実装しました.

【環境】

  • OS: Ubuntu 16.04.4 LTS
  • GPU: GeForce GTX 1080
  • Python: 3.6.5
  • Chainer: 4.2.0
  • MeCab: 0.996 (単語のわかち書きに利用)

【データセット】

参考論文では,データセットとして6400万件の楽天のレビューデータを利用していましたが,都合によりこのデータは利用できないので社内で利用しているデータを利用します.表1がデータセットの一例になります.それぞれの文には極性を表す正規化スコアが存在し,1に近いほどポジティブな内容,0に近いほどネガティブな内容となっています.

表1: データセットの一例
表層 正規化スコア
バイバイまた明日また会おうね 0.86665
今何か言ったごめんちょっとぼーっとしてて聞いてなかった 0.3
毎日雨が降って鬱陶しいですね。 0.142857143
言葉の使い方が間違ってるんではないでしょうか。 0.285714286
やっほー元気かい 1

このデータをトレーニングデータとテストデータに分割して利用します.データセット内のボキャブラリは,word-levelでは2905, character-levelでは1302ですが,radical-levelにしたことで685まで減少しました.データがより大規模であれば,大半の漢字は少数の部首に集約されるため,ボキャブラリの減少率は大きくなりそうです.

  • トレーニングデータ: 1000件
  • テストデータ: 100件
  • ボキャブラリ: 685(radical-level)

【前処理】

データに対して以下の前処理を行います.

  • 正規化スコアが0.5以上であれば1, それより低ければ0とする
  • データ内のボキャブラリ(radical-level)辞書を作成してEmbeddingに利用する

データの比率は,トレーニングデータで「Positive:Negative = 470:530」,テストデータで「P:N = 54:46」となっています.提案手法では漢字を部首に変換する必要があるので,IDS-UCS-Basic.txt の部首情報を利用します.ただし,IDS-UCS-Basic.txt には漢字に対応する部首が「語」→「言,吾」のように記載されているため,「語」→「言,吾」→「言,五,口」のように再帰的に部首を取得して,完全な部首辞書を作成します.その後,この辞書を用いてデータ内のボキャブラリ辞書を作成してEmbeddingに利用することになります.少し面倒ですね…

【パラメータ】

モデルのパラメータは以下のように設定しました.最適化手法は参考論文と同様にRMSpropを利用します.入力文は単語数を基準に20の固定長として切り捨て・ゼロパディングで処理します.なお,データセットに含まれる文の単語長は平均が12.7, 最長が64, 最短が2, 中央値が11でした.

  • Optimizer: RMSprop (learning rate=0.001, decay rate=0.9)
  • Word Length: 20
  • Mini Batch size: 50
  • Epoch: 50
  • 重み初期値: 標準正規分布

【結果】

以下の図3がEmbedding次元を変化させたときの推定精度になります.これを見ると,Test AccuracyはEmbeddingの次元に依らず0.60~0.65程度となっています(参考論文と同じ15次元では少し悪い?).十分な精度とは言えず,少し過学習気味なのも気になります.

図3. Embedding次元を変化させた場合の推定精度
図3. 埋め込み次元を変化させたときの推定精度

過学習を解消するために,Weight Decay(rate=10e-6)とGradient Clipping(threshold=1.0)を適用したのですが,全体的に精度が下がってしまっています(図4).

図4. Weight DecayおよびGradient Clippingの適用後
図4. Weight DecayおよびGradient Clippingの適用後

ただし,Embedding dim=45の時はそこまで精度の低下が見られないので,これを固定してWord Length(入力単語数)を変化させたのが図5になります(WeightDecay,GradientClippingは適用せず).これを見ると,Word Lengthを40や50とした方が学習が安定していることがわかります.そこで試しにWord Length=40として,Epochを100まで学習させたところ,精度が0.7を超えてくるようになりました(図6).

図5. Word Lengthを変更した場合の精度(Embedding dim=45)
図5. Word Lengthを変化させたときの推定精度(Embedding dim=45)
図6: Word Length=40, Embedding dim=45, Epoch=100
図6: Epoch=100 (Word Length=40, Embedding dim=45)

他にも精度向上のためにやれることは色々ありそうですが,今回のデータセットではこれくらいが限界そうなので評価は以上にしようと思います.今回はやっていませんが,同じデータセットでcharacter-level[3]の手法と比較もしてみたいですね.

まとめ

今回はCNNやBi-directional-LSTMを用いたradical-levelでのエンコーダーについて紹介しました.radical-levelで埋め込むことでボキャブラリを大きく削減できましたが,論文のように高い精度を実現することはできませんでした.その原因として,論文のような大規模なデータを利用できず,部首の特徴を十分に学習できなかったということが考えられます.[5] によれば,Character-levelでは大規模なデータセットに対して良い結果が得られ,小規模なデータセットでは単純なモデルにも負けてしまうらしいです.今回はradical-levelですが,データセットが1000件程度しかないので同様のことが言えるかもしれません.

参考文献

[1] Yuanzhi Ke, Masafumi Hagiwara, “CNN-encoded Radical-level Representation for Japanese Processing”, Transactions of the Japanese Society for Artificial Intelligence, vol. 33 no. 4, p. D-I23-1-8 (2018).

[2] Rico Sennrich, Barry Haddow, Alexandra Birch , “Neural Machine Translation of Rare Words with Subword Units”, In Proceedings of the 54th Annual Meeting of the Association for Computational Linguistics (2016).