概要
手書き数字画像データセットであるMNISTを取得し、ニューラルネットワークのサンプルで扱える形にする手順を整理する。
MNISTは、画像分類の入門でよく使われるデータセットで、入力データ、ラベル、訓練データ、テストデータの関係を確認するのに向いている。
ここでは、データの仕様、ダウンロード処理、画像としての表示確認までを扱う。
この記事の構成
- MNISTとは
MNISTの意味と基本的な考え方を整理。 - MNISTのデータ仕様
MNISTのデータ仕様の意味と要点を具体例から整理。 - MNISTのダウンロード
MNISTのダウンロードの手順と確認ポイントを整理。 - 画像データ表示確認
画像データ表示について、確認する項目と結果の見方を整理。
概念の説明と実装サンプル
MNISTとは
- データセットの構成
MNIST(Modified National Institute of Standards and Technology database)とは、0~9の手書き数字で構成され、訓練画像60,000枚とテスト画像10,000枚が用意された画像データセットである。
また、手書き数字の訓練画像が60,000枚、テスト画像が10,000枚の「1枚」に対して画像データとその画像の正解となるラベルデータがペアとなっており、下記の4つのファイルで構成されている。
- train-images-idx3-ubyte : 学習用 画像データセット(60,000枚)
- train-labels-idx1-ubyte : 学習用 ラベルデータセット(60,000個)
- t10k-images-idx3-ubyte : テスト用 画像データセット(10,000枚)
- t10k-labels-idx1-ubyte : テスト用 ラベルデータセット(10,000個)
MNISTのデータ仕様
- 画像・ラベルデータの形式
機械学習では画像を数値として扱う必要があるため、バイナリデータとなっており、画像とラベルデータが紐付いている。
※ 以下の画像・ラベルの形式は、MNISTで使われるIDXファイルのヘッダーとデータ配置を整理したもの。
以下、画像とラベルのフォーマット仕様。
-
画像データのフォーマット(train-images-idx3-ubyte、t10k-images-idx3-ubyte)
offset type value description 0000 32 bit integer 0x00000803(2051) 識別子(定数) 0004 32 bit integer 60000 画像データの数 0008 32 bit integer 28 1画像あたりのデータ行数 0012 32 bit integer 28 1画像あたりのデータ列数 0016 unsigned byte 0 ~ 255 1つめの画像の1ピクセル目の値 0017 unsigned byte 0 ~ 255 1つめの画像の2ピクセル目の値 ... ... ... ... xxxx unsigned byte 0 ~ 255 最後の画像の784ピクセル目の値 -
ラベルデータのフォーマット(train-labels-idx1-ubyte、t10k-labels-idx1-ubyte)
offset type value description 0000 32 bit integer 0x00000801(2049) 識別子(定数) 0004 32 bit integer 60000 or 10000 ラベルデータの数 0008 unsigned byte 0 ~ 9 1つ目のデータのラベル 0009 unsigned byte 0 ~ 9 2つ目のデータのラベル ... ... ... ... xxxx unsigned byte 0 ~ 9 最後のデータのラベル
-
MNISTのダウンロード
- データ取得と読み込み
下記、
mnist.pyを使用し、MNISTをダウンロードする。Git(deep-learning-from-scratch):https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/dataset/mnist.py
-
リポジトリをクローン
$ cd gitlocalrep $ git clone https://github.com/oreilly-japan/deep-learning-from-scratch.git Cloning into 'deep-learning-from-scratch'... remote: Enumerating objects: 381, done. remote: Total 381 (delta 0), reused 0 (delta 0), pack-reused 381 Receiving objects: 100% (381/381), 4.93 MiB | 4.16 MiB/s, done. Resolving deltas: 100% (197/197), done. -
カレントディレクトに移動
mnist.pyの利用時は、カレントディレクトを ch01、ch02、ch03 … ch08 のいずれかで実施する必要がある。
ここでは、ch03から実施。$ cd deep-learning-from-scratch/ch03 -
ダウンロード
下記、load_mnistによってMNISTデータセットのダウンロードを行っているが、初回のみオンラインである必要があり数分かかる。
初回で読み込み時にpickleというローカルファイルが作成され、ダウンロード結果を保持しているので、2回目以降は、オフラインかつ、すぐに処理が終わる。
※ Pythonのpickleは、Pythonオブジェクトをファイルへ保存・復元する機能。信頼できないpickleを読み込むと任意のコードが実行される危険があるため、この例では取得元を確認したファイルだけを使用する。$ python >>> import sys, os >>> sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定 >>> from dataset.mnist import load_mnist >>> >>> (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False) # MNISTデータセットのダウンロード Downloading train-images-idx3-ubyte.gz ... Done Downloading train-labels-idx1-ubyte.gz ... Done Downloading t10k-images-idx3-ubyte.gz ... Done Downloading t10k-labels-idx1-ubyte.gz ... Done Converting train-images-idx3-ubyte.gz to NumPy Array ... Done Converting train-labels-idx1-ubyte.gz to NumPy Array ... Done Converting t10k-images-idx3-ubyte.gz to NumPy Array ... Done Converting t10k-labels-idx1-ubyte.gz to NumPy Array ... Done Creating pickle file ... Done! >>> >>> print(x_train.shape) # データ形状の確認:学習用 画像データセット (60000, 784) >>> print(t_train.shape) # データ形状の確認:学習用 ラベルデータセット (60000,) >>> print(x_test.shape) # データ形状の確認:テスト用 画像データセット (10000, 784) >>> print(t_test.shape) # データ形状の確認:テスト用 ラベルデータセット (10000,) >>> -
load_mnist関数の概要
引数 normalize は、入力画像を0.0 ~ 1.0 に正規化するかどうかBool値で設定。
Falseの場合、入力画像のピクセルは 0 ~ 255 となる。
引数 flatten は、入力画像を1次元にするかどうかBool 値で設定。
Falseの場合、入力画像は1 * 28 * 28 の3次元配列として格納され、Trueの場合、1次元配列(要素:784)として格納される。
引数 one_hot_label は、ラベルを one_hot表現で格納するかBool値で設定。
one_hot 表現の場合は、正解となるラベルのみ 1 でそれ以外は、0 の配列となる。
戻り値は、(訓練画像, 訓練ラベル), (テスト画像, テストラベル)の形式でMNISTデータを返す。
-
画像データ表示確認
- 手書き数字画像の表示
ch03/mnist_show.pyに訓練画像1枚目「5」の確認用ソースコードが記載されている。
下記は、この中のshowにあたる箇所をsaveに置換え、画像ファイルを出力するサンプル。$ python >>> import sys, os >>> sys.path.append(os.pardir) >>> import numpy as np >>> from dataset.mnist import load_mnist >>> from PIL import Image >>> >>> def img_save(img): ... pil_img = Image.fromarray(np.uint8(img)) ... pil_img.save('pid19_1.png') # *1 mnist_show.py では、pil_img.show() ... >>> (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False) >>> >>> img = x_train[0] >>> label = t_train[0] >>> print(label) 5 >>> print(img.shape) (784,) >>> img = img.reshape(28, 28) >>> print(img.shape) (28, 28) >>> img_save(img) # *1 mnist_show.py では、img_show() >>>- pid19_1.png
期待通り、数字の手書き画像「5」が出力された。
- pid19_1.png
まとめ
- MNISTは手書き数字の画像と正解ラベルから構成され、画像はピクセル値の配列として扱われる。
- shapeや画像表示を確認すると、配列の形と実際の画像を対応付けやすい。
- 訓練データは学習、テストデータは評価に使い、両者を混ぜない。
- 正規化の有無によってピクセル値の範囲が変わるため、後続処理の前提をそろえる。