2015/10/17

[caffe?]lmdbでデータを見てみる

CaffeでDeep Learning つまずきやすいところを中心に
こちらを見ると、build/tools/convert_imageset.binを使うと学習画像やテスト画像をDBに取り込んでくれるらしい。
デフォルトのDBは、lmdbというもののようだ。
あれ、私は画像じゃなくて、他のをやりたいのだが・・・

というわけで、どういうデータを入れたらいいのか、mnistで取り込んだデータを見てみることにした。


$ sudo apt-get install lmdb-utils
$
mdb_stat examples/mnist/mnist_test_lmdb
Status of Main DB
  Tree depth: 3
  Branch pages: 13
  Leaf pages: 2500
  Overflow pages: 0
  Entries: 10000

ほう。

$ mdb-dump

ない、と怒られた。。。
こちらを見ると、「ppa:cz.nic-labs/knot-dnsがあるよ」ということだった。

PPAってなんだっけねぇ、と調べると、allaboutのページがあった。
私はxubuntuなので、メニューの「Settings > Software & Updates」で、"Other Software"タブを選び、Addした。
こういうのって、apt-get upgradeで何とかなるものだろうか?

$ sudo apt-get update
$ sudo apt-get upgrade
$ mdb_dump

おー、出てきた!

$ mdb_dump examples/mnist/mnist_test_lmdb
VERSION=3
format=bytevalue
type=btree
mapsize=1099511627776
maxreaders=126
db_pagesize=4096
HEADER=END
3030303030303030
0801101c181c229006.....002807
3030303030303031
0801101c181c229006.....002802

(中略)
DATA=END

データの部分の、1行目は連番で、2行目がデータのようだ。
データは、1byte2桁なので、795byteある。
画像は28x28=784。
ということは、795 - 784 = 11byteが付加データ。
こちらによると、MNISTのヘッダは16byteらしいので、それがそのまま載っているわけではない。
MNIST 手書き数字データを画像ファイルに変換する - y_uti のブログ

最初に付いている

0801101c181c22900600...

と、最後に付いている

...000280n

が付加データだろうが、さて、どこからどこまでなのか。
0x1c=28なので、画像のサイズなのだろうが、それだとあまりに画像データに特化しすぎてるよな。。。


あきらめて、検索した。
Caffe: Understanding expected lmdb datastructure for blobs - Stack Overflow

頭の9byteと、お尻の2byteが付加データだった。
データの並びは、caffe.protoのDatumを見ればよいらしい。

message Datum {
  optional int32 channels = 1;
  optional int32 height = 2;
  optional int32 width = 3;
  // the actual image data, in bytes
  optional bytes data = 4;
  optional int32 label = 5;
  // Optionally, the datum could also hold float data.
  repeated float float_data = 6;
  // If true data contains an encoded image that need to be decoded
  optional bool encoded = 7 [default = false];
}

(?_?
protobufの方を見てみよう。
encodingの説明を見てみると・・・

message Test1 {
  required int32 a = 1;
}

こういう設定で、「a=150」とすると、データはこうなるらしい。

08 96 01

へー。0x96 = 150なので、そこはわかるが、前後がわからん。

まず、7bit表現かつリトルエンディアン表現とのこと。
そしてMessageはkey-valueのペアになっていて、最初はkey。
keyは、 (field_number << 3) | wire_type)、という構成。

08
→ 0000_1000 (2進数)
000_1000 (7bit化)
field_number : 0001wire_type : 000

wire_typeが0なのは、表を見ると意味が「Varint」。
field_numberが1なのは、message Test1の「a」という意味。

96 01
→ 1001_0110 0000_0001 (2進数)
→ 001_0110 000_0001 (7bit化)
→ 000_0001 001_0110 (リトルエンディアン)
→ 1001_0110 (つなげた)
→ 0x96 (16進数)
→ 150 (10進数)

他にもルールがあるけど、ごめん、きつい。
あとは、もう、ここのヘッダだけ見ていこう。

0801101c181c229006.....280n

08 : key - field_number=1="channels", wire_type=0=varint型
01 : channels = 0x01
10 : key - field_number=2="height", wire_type=0=varint型
1c : height=28
18 : key - field_number=3="width", wire_type=0=varint型
1c : width=28
22 : key - field_number=4="data", wire_type=2=Length-delimited型
90 06 : Length=0x310=784byte

28 : key - field_number=5="label", wire_type=0=varint型
0n : label=n

データを見ると、頭の方は固定で、labelだけが変わっている。
ここでは、labelが手書き文字が表す数字なのだろう。
最初のリンクで「データセット用意」のクラスに当たるところが、labelになるのかな。


これを、音声や文章のようなストリーミングというか1次元のデータで扱いたいなら、高さか幅を1にして並べればよいのだろう。

でも、lenet_train_test.prototxtを見ても、データが2次元とか、高さとか幅とか、そういうのが見えてこないのよねぇ。
畳み込みニューラルネットって、「深層学習」を読むと2次元のマップに見立て、入力層の広さよりも中間層の広さの方が狭い、みたいな図になっているのだ。
狭いので、中間層の1つのユニットに、入力層のMxNのユニットが結合される、みたいなことになっている。
そういうのが、prototxtになさそうなのだ。

まあ、まだ畳み込みニューラルネットを読んでないので、先走りすぎたかな。

2 件のコメント:

  1. 匿名19:00

    参考にさせていただきました。
    mdb-dump → mdb_dump
    の間違いのようです。

    返信削除
    返信
    1. ありがとうございます。

      apt-upgradeした後は「mdb_dump」と入力しているので、実は最初から入っていて、単に打ち間違えて気付かなかっただけかもしれませんね。
      お恥ずかしい。。。

      削除

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。