kumilog.net

データ分析やプログラミングの話などを書いています。

ImageNetの画像をダウンロードする

f:id:xkumiyu:20171101174312j:plain

ImageNetは大規模な画像データベースで、現在2万クラス1,400万枚を超える画像があります。クラスにはWordNetの単語を用いています。CNNがブレークしたILSVRCというコンペで用いられたりと、ベンチマークとして有名なデータセットです。

画像のダウンロードは、非営利で研究/教育目的に限られるので、それ以外の人は、画像のURLリストを使って自分でダウンロードしなければなりません。

URLリスト作成のための事前準備

今回は、ILSVRC2012で指定された1,000クラスをダウンロードしてみます。1,000クラスのみのURLリストはないので、自分でつくります。作成に必要なものは以下の3つです。

  • すべての画像のURLリスト
  • 1,000クラスのリスト
  • WordNet IDとクラス名の紐付けリスト

すべての画像のURLリスト

http://image-net.org/download-imageurls からダウンロードできます。今回はFall 2011 Releaseをダウンロードしました。容量は334MBで、14,197,122行ありました。

URLリストは、画像IDとURLの2カラムが書かれています。

$ head -n 3 fall11_ulrs.txt
n00004475_6590  http://farm4.static.flickr.com/3175/2737866473_7958dc8760.jpg
n00004475_15899 http://farm4.static.flickr.com/3276/2875184020_9944005d0d.jpg
n00004475_32312 http://farm3.static.flickr.com/2531/4094333885_e8462a8338.jpg

画像IDはユニークなIDで、xxx_yyyのような形式です。xxxWordNetのIDです。

1,000クラスのリスト

ファイルとしてはダウンロードできないので、 http://image-net.org/challenges/LSVRC/2012/browse-synsets からつくります。つくったリストは https://git.io/ILSVRC2012 においています。

$ head -n 3 ILSVRC2012_ClassList.txt
kit fox, Vulpes macrotis
English setter
Australian terrier

1行が1クラスです。

WordNet IDとクラス名の紐付けリスト

http://image-net.org/archive/words.txt からダウンロードできます 。WordNetIDとクラス名の2カラムが書かれています。

$ head -n 3 words.txt
n00001740   entity
n00001930   physical entity
n00002137   abstraction, abstract entity

ダウンロードする画像のURLリストをつくる

1,000クラスからWordNet IDを算出

紐付けリスト(words.txt)をつかって1,000クラスリスト(ILSVRC2012_ClassList.txt)のWordNet IDを求めます。それぞれpandasで読み込んでクラス名でマージします。

import pandas as pd

words = pd.read_csv('words.txt', header=None, delimiter='\t')
words.columns = ['id', 'name']

ILSVRC2012 = pd.read_csv('ILSVRC2012_ClassList.txt', header=None, delimiter='\t')
ILSVRC2012.columns = ['name']

df = pd.merge(words, ILSVRC2012, on='name')
w_ids = list(df['id'])

ここで、ついでに0~999のラベルをつくっておくと、学習に使うときに便利です。

label = pd.DataFrame(df['name'].unique())
label.columns = ['name']
label['label'] = label.index

df = pd.merge(df, label, on='name')

1,000クラスのWordNet IDに含まれるものを抽出

すべての画像のURLリスト(fall11_urls.txt)から、さきほどのWordNet IDに含まれるID(w_ids)だけを抽出します。utf-8でない文字が含まれるようなので、無視するようにします。

import codecs

urls = []
with codecs.open('fall11_urls.txt', 'r', 'utf-8', 'ignore') as f:
    for line in f:
        image_id, url, *tmp = line.strip().split('\t')
        w_id, _ = image_id.split('_')

        if w_id not in w_ids:
            continue

        urls.append({'name': image_id + '.jpg', 'url': url})
pd.DataFrame(urls).to_csv(
        'urllist.txt', index=False, columns=['name', 'url'], header=False, sep=' ')

つくったURLリストには1,341,431ありました。

URLリストをつかって画像をダウンロード

いろいろ試した結果*1wgetでダウンロードしました。

wget-bオプションでバックグラウンド実行できるので、並列にダウンロードできます。-ncオプションですでにあるファイルはダウンロードしないので、途中からやり直すのも楽です。

タイムアウト(-T)は1秒、リトライ回数(-t)は5回にしていますが、適当です。バックグラウンドで実行するときはログファイルができるので、ファイルを-aオプションで指定しないと、1画像1ファイルできるので、大変なことになります。

$ cat urllist.txt | xargs -n 2 ./download.sh
# download.sh
if [ $# -ne 2 ]; then
  exit 1
fi

wget $2 -O $1 -T 1 -t 5 -nc -b -a wget.log

130万画像のダウンロードに3時間くらいかかりました。ファイルの容量は全部で100GBくらいでした。

コードは以下にまとめています。

github.com

*1:はじめ、Pythonのrequestsモジュールをつかったりしていましたが、エラー処理が大変なのと遅いのでやめました。