{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 10種類の小さい画像(CIFAR-10)\n",
"\n",
"*CIFAR-10*というデータセットは多数の小さい画像から構成されている。各画像に対して、その画像に映っているものを表わすテキストラベルが付与されている。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__目次__\n",
"\n",
"- データセットの概要\n",
"\n",
"- (画像、ラベル)の対を調べる\n",
"\n",
"- 作業用のデータを整える\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## データセットの概要\n",
"\n",
"CIFAR-10は、機械学習の研究開発で著名なAlex Krizhevsky氏のトロント大学でのホームページから入手できる。\n",
"\n",
"```\n",
"http://www.cs.toronto.edu/~kriz/cifar.html\n",
"```\n",
"\n",
"このデータセットの源泉となるのは、8000万枚もの小さい画像からなる*Tiny Images*という著名なデータセットである[link]。CIFAR-10はそのごく一部を抜粋したもので、10種類のラベル(*airplane*, *automobile*, *bird*, *cat*, *deer*, *dog*, *frog*, *horse*, *ship*, *truck*)に絞られている。ちなみに、__CIFAR__の略称は(C)anadian (I)nstitute (for (A)dvanced (R)esearchからきている。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"基本情報は以下の通りである。\n",
"\n",
"- 6万枚の画像\n",
"- 大きさは32x32のRGB画像\n",
"- ラベルには10種類ある\n",
"- 各クラスの数は均等で、一クラスにつき6,000枚ある\n",
"\n",
"まずはこのデータセット自体を入手した上で、その中身を覗いてみよう。\n",
"\n",
"```\n",
"$ ls cifar-10-batches-bin\n",
"batches.meta.txt data_batch_2.bin data_batch_4.bin readme.html\n",
"data_batch_1.bin data_batch_3.bin data_batch_5.bin test_batch.bin\n",
"```\n",
"\n",
"`batches.meta.txt`は単なるラベル名を示すテキストで、一行に一つのラベル。あとはバイナリ形式のバッチが6つある。訓練用のもの(`data_batch_*.bin`)と検証用のもの(`test_batch.bin`)からなる。ラベルの分布について、前掲のホームページより引用すると、\n",
"\n",
"> The test batch contains exactly 1000 randomly-selected images from each class. The training batches contain the remaining images in random order, but some training batches may contain more images from one class than another. Between them, the training batches contain exactly 5000 images from each class. \n",
"\n",
"ということであるので、バッチを単独に使うと完全に均一ではないが、バッチを足し合わせるとどのクラスもまったく同じ枚数である。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## (画像、ラベル)の対を調べる\n",
"\n",
"訓練データのファイルを開く。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<_io.BufferedReader name='data/cifar10/cifar-10-batches-bin/data_batch_1.bin'>\n"
]
}
],
"source": [
"\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"toread = \"data/cifar10/cifar-10-batches-bin/data_batch_1.bin\"\n",
"\n",
"f_bin = open(toread, mode=\"rb\")\n",
"\n",
"print(f_bin)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"重要なのは、正しくデータを読めているかどうか検証することである。一番わかやすいのは、自分の目で、「あるはずだ」という中身があることを確かめることである。ドキュメンテーションに目を通すと、今回のバイナリ形式はきわめて単純で、詳細は下記のとおりである。\n",
"\n",
"- データ点の基本形は`<1 x label><3072 x pixel>`である。1バイトがラベルで、そのあとの3072ものバイトは画素値である。したがって、連続する3073バイトが一つの(画像、ラベル)の対に相当するので、各バッチでこれが1万回繰り返される。\n",
"\n",
"- ラベルの取る値は0から9までである。\n",
"- 画像は32x32ピクセルで、一つの画素値に1バイトが使われる。色チャンネルが3つあって、red、 green、blueという順で続く。\n",
"- 画素値の並び方は*row-major*なので、二次元の画像として表示する場合は、配列の行ごとに埋めていく(それに対して、*column-major*の場合は列ごとに埋める)。\n",
"\n",
"この程度の情報があれば難なく準備ができる。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"First byte:\n",
"bytes: b'\\x06'\n",
"int: 6\n"
]
}
],
"source": [
"print(\"First byte:\") # should be a label.\n",
"b = f_bin.read(1)\n",
"print(\"bytes: \", b)\n",
"print(\"int: \", int.from_bytes(b, byteorder=\"big\", signed=False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ここで出てきたPythonのバイトデータ`b'\\x06'`は、最初の1バイトを16進法(hexadecimal)で表記したものである。先頭の``\\x``はバイトごとの区切りを示す。画素値は0から255の値を取るのだが、16進法の2桁を使うと、$0, 1, 2, \\ldots$から$(15 \\times 16^{1} + 15 \\times 16^{0}) = 255$までの整数を表現することができるので、ちょうど良い。\n",
"\n",
"続いて、次の5個のピクセルの値を見てみよう。"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"bytes: b';'\n",
"int: 59\n",
"bytes: b'+'\n",
"int: 43\n",
"bytes: b'2'\n",
"int: 50\n",
"bytes: b'D'\n",
"int: 68\n",
"bytes: b'b'\n",
"int: 98\n"
]
}
],
"source": [
"for i in range(5):\n",
" b = f_bin.read(1)\n",
" print(\"bytes: \", b)\n",
" print(\"int: \", int.from_bytes(b, byteorder=\"big\", signed=False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"いきなり新しい記号がここで出てきたが、たとえば`b';'`などは当然、普通の16進法の表記ではない。PythonはASCII記号を使って表わすことがたくさんある。今回は16進法の`0x3b`を`b';'`で表しているが、大事なのはその中身が正しいかどうかである。`seek()`で最初の画素値に戻り、画像の全ピクセルを読み込んでみる。"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"f_bin.seek(1)\n",
"my_array = np.zeros((32,32,3), dtype=np.uint8)\n",
"for c in range(3): # colour channel\n",
" for i in range(32): # rows\n",
" for j in range(32): # columns\n",
" b = f_bin.read(1)\n",
" my_array[i,j,c] = int.from_bytes(b, byteorder=\"big\", signed=False)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"