SummerEye part7 -高速化-

さすがに1ファイル5秒かかるようでは大量のファイルを扱えない。

それじゃ使い勝手が悪い。

せめてプログレスバーは表示させたいです。

 

時間計測

205KBの猫ちゃん画像一枚でこんな感じです。

start upload_to_BLOB: 0.0042650699615478516sec
end upload_to_BLOB: 0.5201702117919922sec
start save_file: 0.520233154296875sec
end save_file: 0.6028749942779541sec
start get_description: 0.6029150485992432sec
end get_description: 4.062183141708374sec
description: a-cat-that-is-looking-at-the-camera
start create_zip: 4.062453031539917sec
end create_zip: 4.063966989517212sec

 

案の定というかComputer Vision APIを叩くとこに時間がかかっています。

ここだけで3.4secぐらい。

ここはもう画像サイズに依存する通信速度というよりは、APIサーバ内での分類に時間がかかってるんじゃないかなと予想。

つまりこっち側でできることはないのでは?

(後述しますが、できることたくさんありました)

 

BLOBを使わない

現在、APIを叩く時 BLOBのURLを使っているんですが、サーバ内のパス指定でやったらどうなるか検証します。

start upload_to_BLOB: 0.0044820308685302734sec
end upload_to_BLOB: 0.21289300918579102sec
start save_file: 0.2129528522491455sec
end save_file: 0.32558703422546387sec
start get_description: 0.32562994956970215sec
end get_description: 3.256577968597412sec
start create_zip: 3.2568159103393555sec
end create_zip: 3.258357048034668sec

 

ちょっと良くなった?get_descriptionで2.9secぐらい。

こうなるともはやBLOBに保存することは不要。。。

 

BLOB保存を抜いてみる。

これで0.2secぐらい早くなるはず。

start save_file: 0.003812074661254883 sec
end save_file: 0.00434112548828125 sec
start get_description: 0.004353046417236328 sec
end get_description: 3.1944820880889893 sec
start create_zip: 3.195725202560425 sec
end create_zip: 3.2059221267700195 sec

 

全体としてあまり変わらず。

多分API側の速度にムラがあるんだろうなぁ。

結局ディスクリプションの取得に3secくらいかかるか。

 

ファイルサイズでの速度比較

重いファイルでも比較。

150KBの画像で3.1sec、

1.4MBの画像で3.8sec。

 

画像の重さでも結構変わります。

保存後、APIを叩く前に軽くするとか?

 

ネコ、イヌ、レッサーパンダの3枚の画像をあげてみると9secぐらいかかってしまいました。

うーん。なんだかなぁ。

 

grequestsを使ってHTTPリクエストを非同期処理

非同期処理的にHTTPリクエストを行える便利なライブラリがあるとのことです。

 

とりあえず入れてみる。

pip install grequests

 

使い方にちょっと戸惑いながらもこんな感じで実装。

(paramsとかは事前に定義済みです)

def get_description_list(paths):
    description_list = []
    url = "http://westcentralus.api.cognitive.microsoft.com/vision/v1.0/analyze?%s" % params

    headers = {
        'Content-Type': 'application/octet-stream',
        'Ocp-Apim-Subscription-Key': subscription_key,
    }
    res = (grequests.post(url, headers=headers, data=open(p, 'rb').read()) for p in paths)
    res_list = grequests.map(res)

    for r in res_list:
        parsed = json.loads(r.text)

        description = parsed["description"]["captions"][0]["text"].replace(" ", "-")
        description_list.append(description)

    return description_list

 

150KB、200KB、800KBの3ファイルを投げてみる。

start get_descriptions: 0.03051304817199707 sec
end get_descriptions: 3.2018191814422607 sec
start create_zip: 3.2022221088409424 sec
end create_zip: 3.2059621810913086 sec

 

早い!9secぐらいだったのがほぼ1ファイルの時と変わらない3secになりました!

 

試しに10ファイル投げてみる。

こんな感じのファイルを投下。

start get_descriptions: 0.06829094886779785 sec
end get_descriptions: 3.9539849758148193 sec

 

10ファイルで4sec弱!これなら十分使えそうです。

 

気になる精度は、

いい感じです。

 

レッサーパンダが「panda-bear」、ネズミが「rodent」、ウサギが「small-animal」なところがもう少し細かく分類できるといいなと思いますが。

他はちゃんと動物の名前取れているので検索の役に立ちそうです!

 

デモ動画

 

並列処理

今回実装には至りませんでしたが、multiprocessingやJoblibを使うとさらに並列処理を行うことができるようです。

ちなみに今使っているApp ServiceのF1インスタンスのコア数は「Shared(60 CPU 分/日)」と書いてあります。

よくわからない。

 

コア数の多いインスタンスに切り替えられたら実装しようと思います。

クアッドコアなら最高4分の1になる可能性がありますし。

 

現段階10ファイル4secなので、40ファイルが4sec、100ファイル10secで処理できると期待できます。

なかなか実用的ではないでしょうか。

 

次回

デザインも何もない状態なので、ある程度整えます。

 

参考

コメントを残す