ファッションアイテムの画像からの特徴抽出とマルチスケールなCNNの効果

同僚に3ヶ月のディープラーニング禁止令を言い渡したデータサイエンティストの中村です。 VASILYではスナップ画像に写っているモデルさんが着ている服と似ている服を検索する画像検索エンジンを開発しています。

ファッションアイテムを探す際、デザイン(アイテムの色や模様)はとても重要なファクターになります。 ファッションアイテムの画像検索システムも当然、色や模様のような局所的な特徴を捉えた検索を提供する必要があります。ところが判別タスクにおける歴代チャンピオンモデルと同様のCNNを使って特徴抽出を行うと、局所的な特徴が失われて似ていないアイテムがヒットしてしまうという問題がありました。

f:id:vasilyjp:20170423091424p:plain

そこで、局所的な特徴の保存と表現能力の向上を期待して、モデルに浅いネットワークを追加してマルチスケールに拡張しました。 今回はこの取り組みについて紹介したいと思います。

f:id:vasilyjp:20170423103020p:plain

スナップ画像から商品画像を検索する

スナップ画像から商品画像を検索する方法については過去にもテックブログで紹介しています。

tech.vasily.jp

検索クエリはスナップ画像をトリミングした画像、検索対象はECサイトにあるような商品画像です。両者は性質が異なるため、ドメインを跨いだ画像検索となります。

f:id:vasilyjp:20170419172556p:plain

このようなタスクにはCNNとTriplet Lossを用いた学習が有効であるというのが上記ブログの主張です。

局所特徴量の損失

画像認識におけるCNNの性能は今更紹介するまでもありません。CNNを使って抽出した特徴量は判別タスク以外にも様々な用途が存在します。もちろん検索にも有効なのですが、ファッションアイテムの画像検索に限定すると、判別タスクと同じモデルで抽出した特徴量はかえって精度を悪化させる場合が存在すると考えています。

判別タスクと異なり、ファッションアイテム検索において画像の局所的な特徴は重要な情報です。 例えば、服を買おうと思っている人の中に「カテゴリがシャツであればなんでもいい」と考える人は少ないと思います。人によって選ぶポイントは様々ですが、条件に色や模様が含まれる場合は多いと思います。

色や模様といった単純な構造は、本来1回フィルタを畳み込むだけで抽出できるのですが、CNNで何回もフィルタを畳み込むうちに失われてしまうと言われています。 カテゴリ判別等に有効な複雑な構造ももちろん大事なのですが、ファッションアイテム検索用のネットワークでは同時に単純な構造も抽出できる能力を持たせる必要があります。

マルチスケールなCNN

Wang2014*1を参考に、より表現能力の高い特徴を抽出する能力を期待してモデルに浅いネットワークを追加し、マルチスケールに拡張しました。

f:id:vasilyjp:20170419180345p:plain

浅いネットワークの仕組みは以下のとおりです。 図の中央のパスの入力は、元の画像(224x224 x 3)を57 x 57 x 3に解像度を落とした画像です。これにフィルタを畳み込んだ後に最大プーリングによって4 x 4 x 96のテンソルにします。 下のバスも同様の操作を施しますが、入力画像は更に解像度を落として29x29x3とします。

実装上は低解像度の画像を入力するのではなく、平均プーリングを使って解像度を落とします。 ネットワークの定義は以下の様になります。

class MultiscaleNetHingeTriplet(chainer.Chain):

    def __init__(self, margin=0.2):
        self.margin = margin
        self.train = True

        self._layers = {}

        # 深いネットワークの定義 
        # self._layers['conv1_1'] = ...

        # 浅いネットワークの定義
        self._layers['conv2_1'] = L.Convolution2D(None, 96, 3, stride=4, pad=1, wscale=0.02*np.sqrt(3*3*3))
        self._layers['norm2_1'] = L.BatchNormalization(96)
        self._layers['conv3_1'] = L.Convolution2D(None, 96, 3, stride=4, pad=1, wscale=0.02*np.sqrt(3*3*3))
        self._layers['norm3_1'] = L.BatchNormalization(96)

        # 合流後の層
        self._layers['fc4_1'] = L.Linear(4096, 4096)
        self._layers['fc4_2'] = L.Linear(4096, 256)

        super(MultiscaleNetHingeTriplet, self).__init__(**self._layers)

forwardは画像を引数に取ります。

    def forward(self, x):
        test = not self.train

        # 深いネットワークのforward
        # h1 = self.conv1(x)
        # ...

        h1 = F.normalize(h1)        # 深いネットワークの出力は正規化する

        # 浅いネットワークのforward
        # 平均プーリング操作によるdown sampling
        h2 = F.average_pooling_2d(x, 4, stride=4, pad=2)
        h2 = F.max_pooling_2d(
             F.relu(self.norm_s1(self.conv_s1(h2), test=test)), 5, stride=4, pad=1)
        h3 = F.average_pooling_2d(x, 8, stride=8, pad=4)
        h3 = F.max_pooling_2d(
             F.relu(self.norm_s2(self.conv_s2(h3), test=test)), 4, stride=2, pad=1)

        h23 = F.concat((h2, h3), axis=1)
        h23 = F.normalize(F.reshape(h23, (x.data.shape[0], 3072)))

        h = F.concat((h1, h23), axis=1)

        h = F.normalize(F.relu(self.fc4_1(h)))
        h = self.fc4_2(h)
        return h

実験

浅いネットワークの効果を検証します。深いネットワークにはGoogLeNetを使いました。 深いネットワークにはVGGやResNetも使えますが、モデルパラメータ数と学習の簡単さという点でGoogLeNetを選びました。

余談ですが、モデルパラメータ数が増えると当然学習の難易度も上がります。データや計算リソースが限られている環境で実験を行う際はGoogLeNetのような軽量なネットワークから始めるのがおすすめです。 歴代チャンピオンモデルのパフォーマンス比較はCanziani2016*2がとても参考になります。

結果

上段は深いネットワークのみの検索結果、中段は浅いネットワークのみ、下段は浅いネットワークと深いネットワークを組み合わせたモデルの結果です。 浅いネットワークが入ったモデルは、クエリ画像のアイテムと似た色のアイテムを探す能力があることがわかります。マルチスケールなCNNの検索結果はアイテムの大まかな形状もクエリ画像と似ており、検索結果の分散も他のモデルと比べて小さいように見えます。

f:id:vasilyjp:20170419192141p:plain

f:id:vasilyjp:20170419192335p:plain

f:id:vasilyjp:20170419193131p:plain

f:id:vasilyjp:20170419194133p:plain

定量評価

Street2Shopデータセット*3で簡単な実験を行いました。train/testを9:1で分割して全カテゴリ混ぜて学習させました(本当はカテゴリ毎に学習させたほうが良いです)。評価は幾つかのカテゴリについてRecall@5とnDCG@5を計算しました。 なお、検索には近似近傍探索を使っているため、値はあくまで参考値です。

Recall@5

Arch bags tops dresses skirts
deep 0.35 0.38 0.26 0.79
shallow 0.50 0.33 0.29 0.83
deep+shallow 0.52 0.35 0.30 0.81

nDCG@5

Arch bags tops dresses skirts
deep 0.26 0.28 0.18 0.60
shallow 0.36 0.27 0.20 0.66
deep+shallow 0.42 0.27 0.22 0.68

まとめ

モデルに浅いネットワークを追加することで検索結果が改善しました。浅いネットワークだけでも簡単な特徴なら抽出できること、深いネットワークと組み合わせることで特徴量の表現能力が増すことを確認しました。

今後は事前学習や誤差関数を高度化することでより高精度な検索を達成していきたいと考えています。

最後に

VASILYでは、最新の研究にアンテナを張りながら、同時にユーザーの課題解決を積極的に行うメンバーを募集しています。 興味のある方はこちらからご応募ください。

*1:Jiang Wang, Yang Song, Thomas Leung, Chuck Rosenberg, Jingbin Wang, James Philbin, Bo Chen, Ying Wu. Learning Fine-Grained Image Similarity with Deep Ranking. In Proc. CVPR. 2014.

*2:Alfredo Canziani, Eugenio Culurciello, Adam Paszke. An Analysis of Deep Neural Network Models for Practical Applications. arXiv. 2016.

*3:M. Hadi Kiapour, Xufeng Han, Svetlana Lazebnik, Alexander C. Berg, and Tamara L. Berg. Where to Buy It: Matching Street Clothing Photos in Online Shops. In Proc. ICCV. 2015.