畳み込み(CNN)とSpatial Pyramid Pooling(SPP-net)を使ってテキスト分類


以前、Recurrent Convolutional NNでテキスト分類という記事を作成し、画像ではない方のR-CNNでテキスト分類をするコードを書きました。

この時、「covolution_2dではx軸固定の畳み込みができない」と書いたのですが、実際のところは画像を対象とした処理と同様の畳み込み方法(x, y方向に移動しながらフィルタを適用する)でも性能は出るようです。実際にその手法でChainer実装をされた方がいました。

単語埋め込みベクトルを語順にそのままつなげて大きな2次元ベクトルを作り、それを用いて分類器の学習ができるわけですが、テキストという性質上、そのサイズは文章の長さに依存してしまいます。そのため、先の実装では一度すべての文章の最大長を計り、そのサイズに固定して(必要なら0パディングして)処理を行っています。

これはこれでひとつの方法なのですが、プーリング層にSpatial Pyramid Poolingを用いることで、任意長の入力を固定長のベクトルにすることができます。これを利用することで可変長入力を受け付けるモデルができます。
Chainerではspatial_pyramid_pooling_2d関数として実装されているので、max_pooling_2dをこれに置き換えて、中間のFCレイヤーのユニット数をSPPの出力と合わせれば完成です。

    def __call__(self, x):
        h1 = F.spatial_pyramid_pooling_2d(F.relu(self.conv1(x)), 2, F.MaxPooling2D) # max_pooling_2dと入れ替え
        h2 = F.dropout(F.relu(self.l1(h1)))
        y = self.l2(h2)
        return y

test accuracyはオリジナルと同等程度出ています(75%前後)。

その他の修正点

  • テキストデータのダウンロード、input.datの生成までを行うMakefileを追加
    • word2vecモデルはwgetでダウンロード可能な一意のURLがないので、配布元から取得してください
  • load_dataの高速化
    • 巨大なnumpy配列に対するappendは遅くなるのであらかじめ必要な領域を確保
  • CPU指定時に動かない(xp未定義)を修正