LoginSignup
34
35

More than 5 years have passed since last update.

美女を見分けられない機械はただの機械だ:Pythonによる機械学習用データセット生成

Last updated at Posted at 2018-08-19

データセットとは

機械学習におけるデータセットとは、学習に必要な情報がまとまっている「You これで機械学習やっちゃいなよ」セットである。様々なデータセットがネット上に公開されており、
MNISTの手書き数字のデータセットなどはとても有名である。

データセット生成方法の情報が少ない

web上のデータセットを用いて機械学習の勉強をする際には問題にならないが、勉強を進めていくと「これは自分オリジナルだぜ」的な機械学習を試しにさせてみたくなるのが漢の性である。

しかし、ここで壁にぶち当たる。。。
機械学習自体の情報に比べて、データセット生成に関するが圧倒的に少ない!と拙者は思う。プロフェッショナルな方々は「データセット?そんなん朝飯前に作れるっしょ?」的な高飛車な感じなのかもしれませんが、拙者みたいな「夏です。機械学習始めました。」みたいな初心者にとっては大事なのである。

なのでどうにかこうにか画像判別用データセット生成に辿り着いたので、その方法を一例として公開しようと思ったわけである。

画像データセット生成までのフロー

拙者は愛すべき美女達(満島ひかり、沢尻エリカ、宮崎あおい、新垣結衣、本田翼)のクラス分類をしたかったので、美女データセットを作成しました。流れは以下になります。

  1. 画像収集
  2. 顔抽出
  3. データセットの形式に変換

画像の集め方、顔抽出

画像の収集方法、顔抽出方法は

美女を見分けられない機械はただの機械だ:OpenCV, Python3による画像からの顔抽出

に書いてあるのでそちらを参照してください。私は合計1500枚ほどの美女の顔抽出画像を集めました。(照)

データセットの形式に変換

データセット生成に当たり画像認識で坂道グループの判別AIの作成を大変参考にさせていただきました。

データセットの呼び出し方を考える

上記の記事ではデータのNumpy配列オブジェクトをpickle漬けにして保存している。しかし拙者は機械学習をPythonではじめる機械学習という本で勉強したので、この本に書いてあるskicit-learnのデータセットの読み出し方がしっくりくる。なのでデータセットを以下のように読み出せるようにプログラムを書いた。

from MyDataSet import beautiful_women

women = beautiful_women.load_beautiful_women()

プログラム

今回私は画像から顔を切り抜いた段階で画像サイズを128*128に統一していたが、サイズを統一していない場合は、2回目のfor文のコメントアウトしてある部分を外してください。

beautiful_women.py

from PIL import Image
import numpy as np
import os, glob

#画像フォルダへの絶対パス
ROOT_DIR = "/Users/tatsuro64/BeautifulWomenCLF/MyDataSet/imgs/"
#各美女の顔画像フォルダ名
WOMEN = ["aoi_ROI", "erika_ROI", "gakky_ROI", "hikari_ROI", "tsubasa_ROI"]

#美女クラス
class BeautifulWomen:
    def __init__(self, data, target, target_names, images):
        self.data = data
        self.target = target
        self.target_names = target_names
        self.images = images

    #キー(インスタンス変数)を取得するメソッド
    def keys(self):
        print("[data, target, target_names, images]")


#画像データをNumpy形式に変換してデータセットを作成
def load_beautiful_women():
    data = []      #画像の一次元データを格納するlist
    target = []    #ラベル(正解)の情報を格納するlist
    target_names = ["aoi", "erika", "gakky", "hikari", "tsubasa"]
    images = []    #画像の2次元データを格納するlist

    for label, woman in enumerate(WOMEN):
        file_dir = ROOT_DIR + woman
        #美女画像を全て取ってくる
        files = glob.glob(file_dir + "/*.jpg")
        print("~~~~~~~~{}の画像をNumpy形式に変換し、Listに格納中~~~~~~~~".format(woman))
        for i, f in enumerate(files):
            img = Image.open(f)
            img = img.convert('L')          #画像をグレースケールに変換
            #img = img.resize((128, 128))    #画像サイズの変更
            imgdata = np.asarray(img)       #Numpy配列に変換
            images.append(imgdata)          #画像データ: 128*128の2次元配列
            data.append(imgdata.flatten())  #画像データ: 16,384の1次元配列
            target.append(label)            #正解ラベルを格納

    print("------------ListをNumpy形式に変換中--------------")
    data = np.array(data)
    target = np.array(target)
    target_names = np.array(target_names)
    images = np.array(images)

    #インスタンスを生成
    beautifulWomen = BeautifulWomen(data, target, target_names, images)

    return beautifulWomen

実際に読み出してみる

test.py
from MyDataSet import beautiful_women

women = beautiful_women.load_beautiful_women()
print(women.data.shape)
print(women.keys())

>>> 実行結果
>>> ~~~~~~~~aoi_ROIの画像をNumpy形式に変換しListに格納中~~~~~~~~
>>> ~~~~~~~~erika_ROIの画像をNumpy形式に変換しListに格納中~~~~~~~~
>>> ~~~~~~~~gakky_ROIの画像をNumpy形式に変換しListに格納中~~~~~~~~
>>> ~~~~~~~~hikari_ROIの画像をNumpy形式に変換しListに格納中~~~~~~~~
>>> ~~~~~~~~tsubasa_ROIの画像をNumpy形式に変換しListに格納中~~~~~~~~
>>> ----------------ListをNumpy形式に変換中------------------
>>> (1456, 16384)
>>> [data, target, target_names, images]

この方法によるメリット・デメリット

pickle漬けで保存する場合は、生成したオブジェクトをバイト列にして保存する。なのでデータセットのNumpy形式に変換するのは一度だけでよく、呼び出し時にはバイト列->オブジェクトの変換をするだけで良い。

一方拙者が選んだ上記の方法は呼び出しごとに、データをNumpy形式に変換してデータセットを生成する必要がある。よって計算コストはpickle漬けに比べて高い。しかし、毎回データセットを画像フォルダから生成するため、後からの画像追加などに対応することが出来てより柔軟である。

34
35
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
35