#chainerでのデータセットの作り方
chainerのmnistのサンプルを見てみても、重用なデータセットの作り方がよくわかりません。
...
# Load the MNIST dataset
train, test = chainer.datasets.get_mnist()
...
どっかから取ってきてるんだろうな−しかわからないこのコードで作られる、このtrain, testの作り方です。
普通にLinearだけを使う場合と、CNNを使う場合とで作り方が違うので、それぞれ書きます。
データは普通の画像を使って、そのラベルは適当に設定します。
chainerでは train,test が必要ですが、どんな形をしているかというと
train, test = chainer.datasets.get_mnist()
print(train[0])
python train_minst.py
(array([ 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. ,
0.71764708, 0.99215692, 0.99215692, 0.81176478, 0.00784314,
...
0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. ], dtype=float32), 5)
の様に、(array([0,0,...,0,0], dtype=float32), 5)
という形をしています。
訓練データの方はfloat32型、ラベルはint32型です。
#準備
どちらの場合でも tuple_dataset という関数を使うのと、CNNでは画像とglobというのも使うので
from chainer.datasets import tuple_dataset
from PIL import Image
import numpy as np
import glob
が必要です。
また、今回はデータセットの作り方ということで、chainerのモデルの作り方・意味はなんとなくでもわかっていないと難しいと思います。
#Linear(普通)の場合のデータセットの作り方
今回は例として、画素値が一列で保存され、その最後にラベルが書かれている行を一つの学習データとして、学習データの数だけ行数のあるcsvの行列データを使います。
例えば、あるデータが
ラベルが1で5x5の画像データであったとして
120,120,120,120,120
130,130,130,130,130
140,140,140,140,140
150,150,150,150,150
160,160,160,160,160
だとしたら
120,120,120,120,120,130,130,...150,150,160,160,160,160,160,1
のように、一つの学習データが一行として書かかれます。
data.txtの最後の1,5,3,5がラベルです。
...
0,0,11,1,388,484,236,268,500,260,212,392,324,220,216,412,204,244,252,292,4,447,403,589,471,434,448,450,430,410,4,434,448,450,430,410,410,410,410,410,1
0,30,11,0,308,368,324,264,372,384,276,216,372,248,212,192,260,204,208,192,4,434,448,450,430,410,410,410,410,410,4,560,220,238,217,305,267,231,202,185,5
0,0,30,1,216,264,268,236,248,272,244,216,284,236,232,180,280,236,188,188,4,560,220,238,217,305,267,231,202,185,4,305,267,231,202,185,185,185,185,185,3
0,30,5,0,220,192,188,188,184,196,204,184,208,188,188,168,204,200,192,160,4,305,267,231,202,185,185,185,185,185,4,418,418,418,418,418,418,418,418,418,5
...
具体的なコードです。
train_data = []
train_label = []
data_raw = open("data.txt")
for line in data_raw:
train = np.array([np.float32(int(x)/255.0) for x in line.split(",")[0:input_num]])
label = np.int32(line.split(",")[input_num])
train_data.append(train)
train_label.append(label)
threshold = np.int32(len(imageData)/10*9)
train = tuple_dataset.TupleDataset(imageData[0:threshold], labelData[0:threshold])
test = tuple_dataset.TupleDataset(imageData[threshold:], labelData[threshold:])
forの中で一つ一つのデータとラベルを作って次々にtrain_dataに追加しています。
そして、一回すべてのデータを入れてから、threshold(閾値)を使って train, test とに分けています。
画素値は0~255なので255で割って0~1に正規化をしています。
#CNNの場合のデータセットの作り方
CNNの入力チャンネルは3でカラー画像を使ったデータセットの作り方になります。
pathsAndLabels = []
pathsAndLabels.append(np.asarray(["./imageDirectory0/", 0]))
pathsAndLabels.append(np.asarray(["./imageDirectory1/", 1]))
pathsAndLabels.append(np.asarray(["./imageDirectory2/", 2]))
# データを混ぜて、trainとtestがちゃんとまばらになるように。
allData = []
for pathAndLabel in pathsAndLabels:
path = pathAndLabel[0]
label = pathAndLabel[1]
imagelist = glob.glob(path + "*")
for imgName in imagelist:
allData.append([imgName, label])
allData = np.random.permutation(allData)
imageData = []
labelData = []
for pathAndLabel in allData:
img = Image.open(pathAndLabel[0])
#3チャンネルの画像をr,g,bそれぞれの画像に分ける
r,g,b = img.split()
rImgData = np.asarray(np.float32(r)/255.0)
gImgData = np.asarray(np.float32(g)/255.0)
bImgData = np.asarray(np.float32(b)/255.0)
imgData = np.asarray([rImgData, gImgData, bImgData])
imageData.append(imgData)
labelData.append(np.int32(pathAndLabel[1]))
threshold = np.int32(len(imageData)/8*7)
train = tuple_dataset.TupleDataset(imageData[0:threshold], labelData[0:threshold])
test = tuple_dataset.TupleDataset(imageData[threshold:], labelData[threshold:])
allData = []の箇所はについてでは
ある人の画像が入っているフォルダごとに読み込んでいるので、 train,test とを作るときに、test に同じラベルのデータしか入らなくなってしまうのでシャッフルしています。
pathsAndLabelsには同じラベルで学習させたい画像データがあるディレクトリとそのラベルを入れます。
ポイントは入力用の画像データを H(高さ)xW(幅)xK(深) から KxHxWにするところです。
pillowのImage.open(path)で読み込んだ画像は前者の行列の形になっているのですが
CNNでは後者の形にしないと入らないので、変えてあげます。
# ここが、上記したポイント部分
# Image.openで取り入れた画像のデータは
# [ [ [r,g,b], [r,g,b], ... ,[r,g,b] ],
# [ [r,g,b], [r,g,b], ... ,[r,g,b] ],
# ...
# [ [r,g,b], [r,g,b], ... ,[r,g,b] ] ]
# のようにrgbがおなじ位置に入ってる感じなのですが、これをそれぞれ赤の画像、緑の画像、青の画像の様にして行列にしないといけません。
# 以下のようなデータにする
# [ [ [ r, r, r, ... ,r ], ここから
# ...
# [ r, r, r, ... ,r ] ], ここまでが赤の画像
#
# [ [ g, g, g, ... ,g ], ここから
# ...
# [ g, g, g, ... ,g ] ], ここまでが緑の画像
#
# [ b, b, b, ... ,b ], ここから
# ...
# [ b, b, b, ... ,b ] ] ] ここまでが青の画像
実際に使っているコードは Githubにあげています。