pythonを使って連番の画像を一括ダウンロードする

pythonを使って連番の画像を一括ダウンロードするスクリプトを書いたので、まとめておく。(スクリプトは一番下)

http://www.xxxxxx/001.jpg
http://www.xxxxxx/002.jpg
.
.

というURLのjpgファイルを一括でダウンロードするためには、
url = "http://www.xxxxxx/"
と編集して実行することで、./pic/以下に一括でダウンロードされる。
1000枚までカウントアップしてダウンロードし続け、ファイルがなくなった時点で終了するスクリプトになっているため、1000枚以上の画像を一括でダウンロードする場合には、for i in range(1000):の部分の数字を変える。

また、
http://www.xxxxxx/a001.jpg
http://www.xxxxxx/a002.jpg
.
.
というように、画像ファイルの前に文字が入っている場合は、
url = "http://www.xxxxxx/a"
と指定すればよい。

これを使えば大抵のサイトの画像が一括ダウンロードできるが、サイト規約で禁止しているサイトもあるため、スクリプト使用前に規約を確認すること。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import urllib.request
import sys
import os

def download():
    path = "./pic/"
    os.mkdir(path)

    url = "保存元のURLを入れる"
    for i in range(1000):
        try:
            url_all = url + str(i+1).zfill(3) + ".jpg"
            urllib.request.urlretrieve(url_all, path + str(i).zfill(3) + ".jpg")
        except urllib.error.URLError as e:
            break

if __name__ == "__main__":
    download()

pythonを使ってディレクトリを簡単にzip圧縮する

pythonを使ってディレクトリを圧縮する方法を検索すると、リストを作成→zipfileを使って圧縮という方法がよく出てくる。
しかし、この方法は無駄に行数が長くなり面倒。
shutilを使うことで、もっと簡単にディレクトリを圧縮することができることがわかったので、まとめておく。

import shutil
shutil.make_archive(output_filename, 'zip', dir_name)

一例として、直下の./testディレクトリを、./arc.zipに圧縮する場合は、このような形になる。
output_filename,dir_nameのどちらも、""で囲う必要があるのがちょっと不思議。

import shutil
shutil.make_archive("./arc","zip","./test")

これでシンプルに圧縮できる!!!

grouped convolution(グループ化畳み込み)の概念を理解する

経緯

mobilenetの実装とモデルを調べる中で出てきた概念として、pointwise convolutionとdepthwise convolutionの理解をまとめてきた。今回はその発展系で、grouped convolutionについてまとめる。
mobilenetは基本的に、pointwise convolutionとdepthwise convolutionを組み合わせた、depthwise separable convolutionの重ね合わせで構成されている。
pointwise convolutionは通常の畳み込み関数のフィルタサイズ1x1にするだけで構成できるので、どのフレームワークでもすぐに実装できるが、depthwise convolutionは実装が特殊、かつ実装方法がまちまちなので、フレームワークによっては使用できないものある。その場合に、depthwise convolutionの代わりにgrouped convolutionを代用することができることを示す。

t-nkb.hatenablog.com

t-nkb.hatenablog.com

grouped convolution(グループ化畳み込み)とは

グループ化畳み込みの歴史は長く、Alexnetの際にはすでに実装されていた。基本的な概念はシンプルで、入力層をレイヤー方向にgroup分割してそれを畳み込みし、最後に結合して出力とするもの。Alexnetでは、片側のグループで白黒の認識フィルタを、もう片側でカラーの認識フィルタを学習することができた…と報告されて話題になっていた。
下図を見れば分かる通り、ほぼdw畳み込みと同じ構造をしており、L=groupとすることでグループ化畳み込みでdw畳み込みが表現できることから、dw畳み込みはgroup畳み込みの一部と考えることもできる。
この考え方はモデル実装時には重要で、darknet等のdw畳み込みが実装されていないフレームワークでも、グループ化畳み込みが実装されていれば、dw畳み込みと同等の動作をさせることができる。ただし、dw畳み込みは実装により速度が大きく変わるため、期待する速度が得られるかどうかはフレームワークによる部分が大きい点は注意が必要である。

[グループ化畳み込み]
f:id:t_nkb:20171227204201j:plain:w400

[dw畳み込み]
f:id:t_nkb:20171227081429p:plain:w400

Depthwise convolution(dw畳み込み)の概念を理解する

経緯

前回、CNNモデルのパラメータ・計算量削減手法の一つであるpointwise convolution(pw畳み込み)について解説した。
pw畳み込みはHW方向の次元を削減し計算量とパラメータを減らすものだったが、それの対極をなすものとして、レイヤー方向の次元を削減するdw畳み込みがあるので、簡単に説明する。
mobilenet等はpw畳み込みと、dw畳み込みの繰り返しであり、この二つの概念が理解できれば、モデルの中身が理解できるはず。

t-nkb.hatenablog.com

概要

f:id:t_nkb:20171227080126j:plain:w300

dw畳み込みの基本的な構成部品は上図の通り、nxnx1の畳み込みフィルタである。基本的には、これを入力層のHxWx1のレイヤに適応し、HxWx1の出力を得ている。
ここで留意すべき点は、畳み込みフィルタ(nxnx1)、入力層(HxWx1)、出力層(HxWx1)共に、層方向の次元が1であること。


f:id:t_nkb:20171227081429p:plain:w400

それでは、入力のレイヤー数が増えた場合はどうなるのか?入力層がHxWxLとなった場合の処理を上図に示す。
先に説明した構成要素である、畳み込みフィルタ(nxnx1)、入力層(HxWx1)、出力層(HxWx1)の次元数を守るために、入力層を一旦1次元のレイヤに分離をし、HxWx1の畳み込みを加えたのち、再び層を結合することで、入力層(HxWxL)、出力層(HxWxL)の次元を確保している。
通常のnxnxLの畳み込みはフィルターが全て層にかかっていることに比べると、計算量が大幅に削減できていることが一目でわかる。
ただし、dw畳み込みでは、各層ごとに畳み込みをするため、層間の関係性は全く考慮されないため注意が必要。通常はこれを解決するためにpw畳み込みとセットで使うことが多い。
#実際の実装ではこの様な処理をしているわけではないが、計算的には等価。一般的な説明とも少し違う説明の仕方だけれど、概念的にはこの理解の方法が一番理解しやすいのでは?

depthwise convolutionのパラメータ数、計算量

dw畳み込みのパラメータ数と計算量についても定量的に示しておく。基本的に、dw畳み込みではレイヤー数は不変なので、入力層のレイヤ数L=出力層のレイヤ数Lとなる。
・パラメータ数はnxnxL、通常のnxn畳み込みのパラメータ数はnxnxLxLであることから、パラメータ数は1/Lで済む。
・計算量も同様にnxnの畳み込みに比べて1/Lとなる。

depthwise convolutionのメリット

最大のメリットは、やはり計算量の削減ができること。特にCPUでは(GPUに比べて)nxnの畳み込みは時間がかかるので、dw畳み込みで畳み込み計算量を減らすことで、大幅に速度を改善できる。

pointwise convolution(1x1の畳み込み)で何をやっているか、概念を簡単に理解する

概要

googlenetやmobilenet等、最近のCNNモデルでは、当たり前の様にpointwise convolution(1x1の畳み込み)を使って次元数を調整する・・・等の説明がなされるけれど、1x1で畳み込んでも結局意味ないじゃん?と最初理解に苦しんだので、自分なりにまとめておく。
「1x1の畳み込み」という言葉だけ聞くと、何の意味もないフィルタの様に思えてしまうけれど、実際は1x1xLbeforeという、各層にまたがる細ながーいフィルタを適応している。以下の図の様な細長いフォルタを使って、入力層から重要そうな部分を選別して取り出し、一つの層にまとめている。この処理を出力層分(HxWxLafter回)繰り返すことによって、層数を簡単に任意の値にできるという点が最大のメリット。

以下に、パラメータ、入出力サイズ、メリットについても自分なりの理解をまとめる。
#自分なりの理解なので、間違っている部分があれば是非ご指摘ください。

[pointwise convolution(1x1の畳み込み)の概念図]
f:id:t_nkb:20171224195604j:plain:w300
1x1の畳み込みを出力一層で適応した場合はこうなる。これが基本の適応系。

f:id:t_nkb:20171224180629j:plain:w300
上記畳み込みフィルタを必要な出力層(Lafter)分だけ適応して、重ねることで任意の総数の出力を得ることができる。
この図では、層数を増やす形で畳み込みフィルタを適応している。
(レシートの裏にメモしたものをスキャンしたので汚い笑)

pointwise convolutionのパラメータ数、計算量

・出力層一層に対するパラメータ数は1x1xLbefore
・よって、Lafter層の出力を得るために必要なパラメータは1x1xLbeforexLafterとなる
・畳み込みに必要な計算量はHxWxLbeforexLafter3x3の畳み込み等に比べると計算量は1/9だが、一般的なフレームワークでは関数呼び出しにかかる時間が加味されるため、ここまで高速にはならない模様

pointwise convolutionの出力

・H,Wのサイズは畳み込み前、後で基本的に同じ(stride=1の場合に限るが、通常はstride=1で適応することが多い)
・出力の総数はパラメータ数を変えることで、任意のサイズを指定することができる(ここが重要!!!)

pointwise convolutionのメリット

最大のメリットは層数を簡単に任意の値に変更できる点。他にも副次的に色々とメリットがある。

・1x1の畳み込みはCPUでも高速で動作する(CPUとGPUの速度差が比較的小さい)
・畳み込みのフィルタサイズを1x1にするだけで実装できるため他の次元削減・拡張手法に比べて圧倒的に実装が楽
・出力の層数を簡単に増減できる
・出力にrelu等を与えることによって、非線形性を増すことができる

【つくばチャレンジ2017】tinyYOLO,YOLO v2を使って対象人物検知モデルを学習させる

つくばチャレンジとは

「つくばチャレンジ」は、つくば市内の遊歩道等の実環境を、移動ロボットに自律走行させる技術チャレンジであり、地域と研究者が協力して行う、人間とロボットが共存する社会の実現のための先端的技術への挑戦です。(下記HPから引用)

つくばチャレンジ

大雑把に言うと、遊歩道2kmをロボットに自律走行させるコンテスト。そのコンテストの課題の中に、エリアのどこかにいる探索対象を発見し、その探索対象に向けてロボットをアプローチさせるという課題がある。
今回、探索対象の検出部分担当として、土浦プロジェクトというチーム名でつくばチャレンジに参加し、探索対象全員の検知に成功したので、その概要を示す。

f:id:t_nkb:20171217181611j:plain
探索対象

つくばチャレンジ2016における成果と課題

つくばチャレンジ2016では、sliding window、CNNを使用して、THETAの全方位画像から、看板が領域内にあるかどうかを識別させることで、探索対象の看板を検出した。
sliding windowとCNNを用いて検出を行う方法は、認識精度は比較的高いが計算負荷が大きく、画像サイズを64*1280ピクセルに縮小して検出させても、JetsonTX1でおよそ3FPS程度が限界であり、探索対象を検出する前にロボットが探索対象を通りすぎてしまうことがあった。
よって、今年度はより高速なR-CNN手法であるYOLOv2,tinyYOLO(Darknet: Open Source Neural Networks in C)を用いて探索対象を検出させることとし、それぞれのモデルにおいて精度の評価を行った。

昨年度のまとめは以下↓
t-nkb.hatenablog.com

学習データの作成

検出モデルを構築する上で最も問題となるのが、学習データをどう集めるかという点である。
特にR-CNNで学習させるためには、画像一枚一枚に対して位置情報等のアノテーションを付与する必要があるが、作業時間が限られていることから、作業できる枚数には限界がある。
そこで、昨年度同様、Deep Learningで用いるデータを「生成」してみた | 技ラボを参考として、探索対象の透過画像20枚と、つくばチャレンジ走行ルートで撮影した背景画像500枚を用いて10000枚の合成画像を作り、学習データとした。
また、画像中から小さな対象物を見つけるためには、Context(探索対象は地面の上に立っている、等の探索対象周辺の文脈情報)が重要だという報告がされている([1612.04402] Finding Tiny Faces)ことから、合成時にカメラの幾何拘束を考慮し、可能な限り現実に近い学習データとなるように考慮して合成を行った。

f:id:t_nkb:20171217174159p:plainf:id:t_nkb:20171217174207p:plainf:id:t_nkb:20171217174229p:plainf:id:t_nkb:20171217174317p:plainf:id:t_nkb:20171217174234p:plain
探索対象の画像例

f:id:t_nkb:20171217175449p:plain
合成画像例
#本画像はContextを考慮"していない"バージョンの合成画像
 Context考慮版では現実にはあり得ない位置(上記画像の中央画像の様な位置)には人を合成しない

YOLOによる学習

Start Training YOLO with Our Own Data - Guanghan Ning's Blogを参考に、上記で作成した画像を、1クラスのR-CNNとしてYOLO,tinyYOLOで学習させた。
学習データサイズは224*1280ピクセル固定とし、バッチサイズ32で25000エポック学習させた。
(注)YOLOに特化したテクニックではあるが、学習モデルを定義するcfgファイル中のrandomの項目を有効にすると、学習データを320*320ピクセル等の複数のサイズにリサイズして学習する。この項目は、ある程度正方形に近い画像を学習させる際には、探索対象のサイズ変化によるロバスト性が上がるため有効とした方が良いが、今回のような、224*1280ピクセルという長方形の学習データに適応してしまうと、逆に性能が悪化してしまうため注意が必要である。

モデルの評価

上記で作成したモデルを、実際のログデータを用いて評価した。テスト精度を向上させるために、多くのテスト画像を用いて評価を行いたいが、学習データの作成同様、画像一枚一枚に対して位置情報等のアノテーションを付与することは非常に時間がかかる。
そのため、「作成したモデルの検出に成功した場合、bounding boxの位置は正しい」という前提を置き、テストデータのアノテーションとして、探索対象が「いるか」、「いないか」、という情報のみを付与し、検出・非検出のRecognition問題としてモデルを評価することとした。
このように検出・非検出のRecognition問題として評価することで、テストデータを安易に大量に生成し、評価することができる。
上記の通りアノテーションを付与した探索対象がいるデータ111枚と、探索対象がいないデータ1000枚を用いて、各モデルの評価を行った。その結果を以下に示す。
このように体系立てて評価することで、以下のことが判った。
・YOLOv2,tinyYOLO共に、合成画像を看板⇒看板+人⇒看板+人(Context考慮)と、探索対象と対象情報周辺の情報(context)を増やすことで精度が向上する
・学習画像が同じであれば、モデルによる精度の差はほとんどない

モデル 合成画像 精度(Precision) 再現率(Recall) TN 処理時間(TX2,1枚)
sliding window+CNN 看板 76.2% 43.2% 98.5% 0.35s
tinyYOLO 看板 81.0% 27.0% 99.3% 0.18s
tinyYOLO 看板+人 88.3% 61.2% 99.1% 0.18s
tinyYOLO 看板+人(Context考慮) 90.9% 63.0% 99.3% 0.18s
YOLOv2 看板 87.3% 43.2% 99.3% 0.22s
YOLOv2 看板+人 91.3% 56.8% 99.4% 0.22s
YOLOv2 看板+人(Context考慮) 91.9% 61.2% 99.4% 0.22s

本走行の結果

つくばチャレンジ2017の本走行では、tinyYOLO(看板+人)バージョンを使用し、TX2上で動作させることで、対象人物全員の検知に成功した。
(Context版は本走行後に評価を行ったため、性能がいいにもかかわらず本走行では使用できなかった)

まとめ

つくばチャレンジ2017において、tinyYOLOを採用し、学習済みモデルをRecognition問題として評価することで性能の良いモデルを選定し、探索対象4人全員の検出に成功した。
ただし、今回探索に成功したのは、つくばチャレンジ2017の課題において、「探索対象は必ず看板の隣にいる」という画像処理しやすい条件が設定されていたためであることが大きく、「迷子の子供を探す」といったより現実に近い課題設定になると、現在の手法の延長では対応できなくなる可能性が高いと感じている。
このような実環境に近い課題を解くためには、現実に近い学習データを生成するsimGAN等、より高度なデータオーグメンテーションが必要になると感じている。

ubuntuにopencvを入れる方法(ubuntu16.04,cuda8.0,gtx1070)

経緯

cuda,cudnnを導入したubuntuopencvを導入しようとすると、make時にエラーが頻発し、なかなか進まない。
一方で、anaconda等を使用してconda install cv2等とするとffmpegがインストールされないため、imshow等の一部の関数が動作しない。

よって、今回うまく導入できた方法をメモとして残しておく。

インストール方法

以下を一行ずつ打っていくだけ

sudo apt-get update
sudo apt-get upgrade

sudo apt-get install freeglut3 freeglut3-dev libtbb-dev libqt4-dev
sudo apt-get install build-essential cmake git pkg-config
sudo apt-get install libjpeg8-dev libtiff4-dev libjasper-dev libpng12-dev
sudo apt-get install libgtk2.0-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get install libatlas-base-dev gfortran

git clone https://github.com/itseez/opencv.git
git clone https://github.com/itseez/opencv_contrib.git
cd opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D INSTALL_C_EXAMPLES=ON -D INSTALL_PYTHON_EXAMPLES=ON -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules -D BUILD_EXAMPLES=ON -D WITH_TBB=ON -D WITH_V4L=ON -D WITH_QT=ON -D WITH_OPENGL=ON ..
make -j$(nproc)
sudo make install
sudo /bin/bash -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig