以前、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未定義)を修正