1 of 31

ZOZO 画像検索におけるChainerの本番運用

株式会社ZOZOテクノロジーズ

MLOps リーダー

瀬尾 直利 そのっつ

Copyright © ZOZO Technologies, Inc.

ML@Loft #9. Deep Learning フレームワークと推論 2019/11/26

2 of 31

2

瀬尾 直利

株式会社ZOZOテクノロジーズ

SRE スペシャリスト

開発部 MLOps リーダー

CSIRT兼任

Twitter/GitHub: @sonots そのっつ

CRuby、Fluentd、Chainer コミッタ

© ZOZO Technologies, Inc.

3 of 31

3

Chainer

1年半ほど週4で開発にJOIN

主に CuPy と ChainerX (C++) を担当

© ZOZO Technologies, Inc.

4 of 31

4

Chainer

。゚(゚´Д`゚)゜。ウァァァン

© ZOZO Technologies, Inc.

5 of 31

5

https://zozo.jp/

  • 日本最大級のファッション通販サイト
  • 1,200以上のショップ、7,300以上のブランドの取り扱い(ともに2019年6月末時点)
  • 常時73万点以上の商品アイテム数と毎日平均3,200点以上の新着 商品を掲載
  • 即日配送サービス
  • ギフトラッピングサービス
  • ツケ払い など

© ZOZO Technologies, Inc.

6 of 31

6

https://wear.jp/

  • 日本最大級のファッションコーディネートアプリ
  • 1,300万ダウンロード突破、コーディネート投稿総数は900万件以上(ともに2019年9月末時点)
  • 全世界(App Store / Google Playが利用可能な全ての国)でダウンロードが可能
  • 200万人以上のフォロワーを持つユーザー(WEARISTA)も誕生

© ZOZO Technologies, Inc.

7 of 31

7

https://zozo.jp/multisize/

  • 身長と体重を選択するだけで理想のサイズの商品が見つかる新しい洋服の買い方
  • ZOZOSUITで得た100万件以上の体型データを活用し、20~50サイズのマルチサイズ(多サイズ)に展開
  • 2019年秋冬アイテムから、人気ブランドのマルチサイズアイテムを販売開始

【参加企業】

 株式会社アーバンリサーチ、株式会社ストライプインターナショナル、

 株式会社デイトナ・インターナショナル、株式会社パル、株式会社ビームス、

 株式会社ベイクルーズ、MARK STYLER株式会社、リーバイ・ストラウス ジャパン株式会社  など

© ZOZO Technologies, Inc.

8 of 31

ZOZO 画像検索とは

  • 画像からアイテムを検出
  • ZOZOTOWN で販売している類似のアイテムを表示する

9 of 31

ZOZO 画像検索とは

  • 画像からアイテムを検出
  • ZOZOTOWN で販売している類似のアイテムを表示する
  • NEW! WEARのスマホウェブでも使えるようになりました

10 of 31

ZOZO 画像検索 アーキテクチャ

11 of 31

(一般的な)画像検索の基本

深層学習を利用してアイテム画像の特徴ベクトルを取得

深層学習を利用して画像からアイテムを検出

取得した特徴ベクトルを予め構築しておいた Approximate Nearest Neighbor(ANN)Index から類似検索

CNN

Feature

12 of 31

(一般的な)画像検索の基本

深層学習を利用してアイテム画像の特徴ベクトルを取得

深層学習を利用して画像からアイテムを検出

取得した特徴ベクトルを予め構築しておいた Approximate Nearest Neighbor(ANN)Index から類似検索

CNN

Feature

Chainer

Chainer

annoy

13 of 31

ZOZO 画像検索ソフトウェアスタック

サーバアプリケーション

  • Python/Flask/Gunicorn/Swagger/gRPC
  • Chainer/CuPy(TensorFlow/TPU も検証)

インフラ

  • 推論 API: Google Kubernetes Engine(GKE)+ Memorystore(Redis)
  • Cloud Load Balancer (LB) / Cloud Armor
  • 学習: Cloud Composer + GKE + Filestore(NFS)
  • Cloud Storage (GCS) / Container Registry (GCR)
  • AWS Route53(ドメイン発行)/ Terraform
  • Datadog / Stackdriver / Sentry

Cloud Composer

Kubernetes Engine

Cloud Memorystore

Cloud Filestore

Cloud Load Balancing

Cloud Armor

Cloud Storage

Container Registry

Stackdriver

14 of 31

ZOZO 画像検索アーキテクチャ全体

Cloud Load Balancing

Cloud Armor

Kubernetes Engine

Cloud Storage

Container Registry

Cloud Memorystore

Developer

画像ストレージ

モデルストレージ

コンテナイメージ

キャッシュ

Cloud Composer

学習

Kubernetes Engine

ANN index

モデル

User

学習

推論

GPU

Cloud Filestore

15 of 31

ZOZO 画像検索推論 API k8s アーキテクチャ

api

8080

api-pool

nns

50051

nns-pool

detect

50051

metric

50051

gpu-pool

gRPC

Cloud Load Balancing

https

http

16 of 31

ZOZO 画像検索推論 API k8s アーキテクチャ

api

8080

api-pool

nns

50051

nns-pool

detect

50051

metric

50051

gpu-pool

gRPC

Cloud Load Balancing

https

http

Chainer

Chainer

annoy

17 of 31

Chainer どうですか

18 of 31

  • 常駐プロセスでも安定
  • メモリリークしない
  • 速度も一定

18

Chainer どうですか

驚くことに(?)安定している

© ZOZO Technologies, Inc.

19 of 31

以上

20 of 31

21 of 31

なぜ Chainer は安定しているのか?

  • 学習でイテレーションをたくさん回すのでメモリリークにシビアな開発
    • 私も気を使って実装していました
  • 開発メンバに高速化が好きな人間が揃っていた
    • 私も(ry
  • 今回は画像処理系のアプリケーションなので CuPy メモリプールに優しい
    • 入力データを同じサイズに正規化してから forward
    • CuPy メモリプールのメモリを綺麗に再利用でき断片化も起きない(はず
  • マルチスレッドにすると怪しいかも?
    • 学習時にマルチスレッドで並列学習するような人は珍しい (熟れてない
    • ZOZO 画像検索では gRPC サーバは1プロセス1スレッド
    • 大丈夫だとは思うが今回は試しそこねた

22 of 31

本番運用における工夫 (Chainer)

23 of 31

Chainer (CuPy) 初回のリクエストが遅い問題

CuPy (cuDNN) autotune を有効化していた

  • 初回に複数のアルゴリズムを試して 1 番速いアルゴリズムを自動選択する機能
  • 推論時に autotune を使うと初回のリクエストだけが異様に遅くなる
  • autotune の結果はオンメモリキャッシュされる

対処

  • 入力条件を揃えて(通常、画像処理系のモデルでは画像は同一サイズに伸長)
  • 起動時に 1 度リクエストを飛ばしておく
    • CuPyメモリプールにGPUメモリをプールしておく効果もありそう
  • Pod が READY になるまでの時間が伸びたので initialDelaySeconds を再調整

24 of 31

Chainer ideep を利用した CPU での推論

推論に GPU は要らないのではないかという仮説

  • 学習時のように複数の画像をまとめて 1 バッチとして GPU に入力するわけではない
  • GPU を使い切れていないのではないかという仮説 → 実際に最大で 50%の使用率
  • Chainer には ideep という Intel CPU に最適化したバックエンドがある

物体検出にかかる時間を比較

  • 32CPU で同等。n1-standard-2 + k80 構成の方が安かった
  • TODO: より軽量なモデルを検討

秒 / リクエスト

値段

CuPy

n1-standard-2 + k80

0.40

$0.549

ideep

n1-highcpu-32

0.43

$1.3136

25 of 31

コンテナにモデルを入れるか入れないか

コンテナイメージのビルド

  • 当初はコンテナにモデルを入れていた
  • ビルドに 1 時間ほどかかり DX(Developer eXperience)に悪い影響

対処

  • コンテナにモデルを入れずに initContainers で Pod 起動時に GCS からダウンロードすることにした

initContainers:

- name: gcloud

image: google/cloud-sdk:latest

env:

- name: METRIC_BUCKET_URL

value: <YOUR_BUCKET_URL>

- name: METRIC_MODEL

value: <YOUR_METRIC_MODEL>

- name: MODEL_DIR

value: "/tmp/models/"

volumeMounts:

- name: models

mountPath: "/tmp/models/"

command:

- gsutil

- cp

- $ (METRIC_BUCKET_URL)/$ (METRIC_MODEL).pickle

- "$ (MODEL_DIR)/metric.pickle"

26 of 31

本番運用における工夫 (Annoy)

27 of 31

annoy がたまに異常に遅い問題

annoy はindexファイルを Linux の disk cache に載せて検索を高速化する設計

  • Indexファイルを mmap(2) with MAP_POPULATE してメモリに載せて検索
  • disk cache なのでメモリから追い出される可能性がある
  • また、経験的にも disk cache に頼ると速度が不安定

対処

  • Indexファイルを tmpfs (linux 標準のオンメモリファイルシステム)に置いた
  • 確実にオンメモリ検索できるようになり速度が安定した

28 of 31

k8sとtmpfs

ちょっと不便な k8s からの tmpfs 利用

  • k8s の pod からでも tmpfs は使える。ただし、ホストの tmpfs を pod 間で共有
  • k8s は tmpfs のサイズ設定に対応していない (ホストメモリの半分が最大)

対処

  • 1 pod 1 node の構成
  • Indexファイルの2倍のメモリ容量のインスタンスを用意して回避 (汗

29 of 31

まとめ

  • ZOZO画像検索のアーキテクチャを紹介
  • Chainer は常駐プロセスサーバでも安定している
      • 起動時に autotune してあげたぐらい
  • Annoy の検索Indexファイルを tmpfs におくと速度が安定する
      • k8s でも tmpfs は使えるがちょっと不便

29

© ZOZO Technologies, Inc.

30 of 31

まとめ

  • ZOZO画像検索のアーキテクチャを紹介
  • Chainer は常駐プロセスサーバでも安定している
      • 起動時に autotune してあげたぐらい
  • Annoy の検索Indexファイルを tmpfs におくと速度が安定する
      • k8s でも tmpfs は使えるがちょっと不便
  • TODO: Chainer を置き換える T T

30

© ZOZO Technologies, Inc.

31 of 31