機械学習

【TensorFlow2入門】ディープラーニングで仮面ライダー俳優を見分けるAIを作る(前編)

スポンサーリンク

ここ最近、ディープラーニングを勉強しているのですが、やはり実際にやってみることが一番!ということでいろいろな方の記事を参考にして、顔認識させるAIを作っていこうと思います。

Pythonの環境構築という初歩の初歩からやっていきますので、初心者の方でも行えるのではないかと思います。

私の大好きな仮面ライダー俳優の顔を見分ける識別機を作成していこうと思います!

何番煎じかは分かりませんが、できるだけ詳しく解説していきますので、TensorFlow2を使ってみたい方は是非参考にしてみてください!

俳優識別AI作成までの全体像

前編は、Pythonの環境構築・ディープラーニング用の画像収集がメインになります。

  1. AnacondaでPythonの仮想環境を構築
  2. TensorFlowをインストール
  3. 画像収集
  4. 収集した画像の顔検出をして、訓練・テストデータに分類
  5. TensorFlowでモデルの構築(後編)
  6. 学習・テスト(後編)
  7. 識別するコードを作成→俳優の顔識別!(後編)

Anaconda環境の構築

Anacondaのインストール

今回はCPU+Windows10という環境で行っていきます。

TensorFlowを使うにはAnaconda環境がいい。ということでAnacondaのインストールから行っていきます。最新版は3.8ですが、ライブラリに対応しているか少し不安だったので3.7を使用することにします。

こちらのページからAnacondaパッケージをインストールします。

ページ下の方へ行き「archive」をクリック

画像に alt 属性が指定されていません。ファイル名: image-59-1024x482.png

2019年10月のWindows-x86 64.exeをダウンロードします。

画像に alt 属性が指定されていません。ファイル名: image-62-1024x122.png

「Anaconda3-2019.10-Windows-x86_64.exe」をダブルクリックして実行します。

画像に alt 属性が指定されていません。ファイル名: image-63.png

「Next」「agree」と進めていきます。

特に設定を変更するところはありません。デフォルトのままで大丈夫です。

画像に alt 属性が指定されていません。ファイル名: image-64.png
画像に alt 属性が指定されていません。ファイル名: image-65.png

以下のように✔を入れてInstallをクリックしてください。

インストールは時間がかかるのでコーヒーでも飲んでゆっくり待ちましょう

画像に alt 属性が指定されていません。ファイル名: image-66.png

これでインストールは完了です!!!

画像に alt 属性が指定されていません。ファイル名: image-67.png

検索欄に「anaconda」と入力しAnaconda Promptを開きましょう。

下記のコマンドを入力してPythonのバージョンを確認しましょう。

目的のバージョンが表示されていればOKです。

python --version

Python 3.7.4

TensorFlow2のインストール

次にTensorFlow2用のPython仮想環境を作成します。下記のコマンドを入力してください。今回はtf2という仮想環境を作成します。

$ conda create -n 環境名 python
#tf2という名前の仮想環境(conda環境)を作成
conda create -n tf2 -y

下記のコマンドを入力すると(base)から(tf2)に変わります。

(base) C:\Users\ユーザー名>activate tf2
(tf2) C:\Users\ユーザー名>

このままTensorFlow2をインストールします。下記のコマンドを入力します。

途中Proceed ([y]/n)?と聞かれたらyと入力しましょう。これも少し時間がかかります。ゆっくり待ちましょう!

#CPUバージョン
conda install -c anaconda tensorflow
#GPUバージョン
conda install -c anaconda tensorflow-gpu

様々なパッケージを自動でインストールしてくれるので、ありがたいですね。

では、実際に動作確認をしてみましょう。以下のコマンドを入力してPythonのインタプリタ画面に移動しましょう。

python
>>> import tensorflow as tf
>>> tf.__version__
'2.1.0'

しっかりTensorFlowがインストールできているのが確認できました!これで思う存分使えます!

今後の実装はこの環境で行っていきます!

ディレクトリ構造

全体のディレクトリ構造は以下のようになっています。各ディレクトリはあらかじめ作成しておいてください!

$ tree
 
dl_tutorial
│
│# APIで収集した画像保存ディレクトリ
├── build_image
├── zeroone_image
├── zio_image
│# 顔切り抜き後のデータ
├── data
│   ├── cutted_build_images
│   ├── cutted_zeroone_images
│   └── cutted_zio_images
│# 訓練・テストデータ
├── split_data
│   ├── train(後から自動作成される)
│   └── validation(後から自動作成される)
├── image_crawle.py# 画像をクロール
├── face_detect.py# 顔を検出
├── make_data.py# 訓練・テストデータに分類
│#顔識別用の分類器
└── haarcascade_frontalface_default.xml

必要なライブラリのインストール

今後の画像収集等に必要なライブラリ等をまとめてインストールしておきます。

#pyshaのインストール
pip install pysha3
#OpenCvのインストール
pip install opencv-python
#PILのインストール
pip install pillow
pip install matplotlib

haarcascade_frontalface_default.xmlという顔識別用の分類器を使用しますので、カスケード分類器のダウンロードを参考にダウンロードしてください。

画像収集(BingAPI使用)

機械学習最初の難関、画像収集です。ここでかなり手こずりました。

分かりやすいように詳しく解説していきますね。

BingAPIサブスクリプションキーの取得

画像収集にはBingのAPIを使用しました。まず、APIの登録が必要です。以下の手順でキーを取得しましょう。

Microsoft Azureの登録サイトにアクセスします。

Bing Search API v7の「APIキーの取得」をクリック

1週間、もしくは1ヶ月無料で使用できますのでどちらかお好きな方を選んで利用してください。

*マイクロソフトのアカウントがない方はアカウント作成の必要があります

無事登録できれば以下のようなサブスクリプションキーが2つ取得できます。

どちらを使用しても構いません。後の画像収集のプログラムで必要になるのでコピーしておきましょう。

画像収集

マーカーを引いてある箇所を変更するだけで画像の収集が行えます。

しかし、countを100にしても100枚以上集まってしまうことがあります。原因はいまいちわかっていません…

分かる方がいたら教えてください。

# -*- coding:utf-8 -*-
import OpenSSL
import requests
import urllib
import hashlib
import sha3
import os

import math
import time
def mkdir(path):
    if not os.path.exists(path):
        os.makedirs(path)

# 引数fをファイル名と拡張子(.は含まない)に分割する
def split_filename(f):
    split_name = os.path.splitext(f)
    file_name =split_name[0]
    extension = split_name[-1].replace(".","")
    return file_name,extension

def download_img(path,url):
    mkdir(path)
    _,extension  = split_filename(url)
    #取得したい画像の形式を指定する
    #if extension.lower() in ('jpg','jpeg','gif','png','bmp'):
    if extension.lower() in ('jpg'):
        encode_url = urllib.parse.unquote(url).encode('utf-8')
        hashed_name = hashlib.sha3_256(encode_url).hexdigest()
        full_path = os.path.join(path,hashed_name + '.' + extension.lower())

        r = requests.get(url)
        if r.status_code == requests.codes.ok:
            with open(full_path,'wb') as f:
                f.write(r.content)
            print('saved image...{}'.format(url))
        else:
            print("HttpError:{0}  at{1}".format(r.status_code,image_url))

 
# image save path
path = "画像を保存したいディレクトリを指定"#例"C:/Users/..."
mkdir(path)

url = "https://api.cognitive.microsoft.com/bing/v7.0/images/search"
 
# 検索キーワード
query = "犬飼貴丈"
count = 50  # 1リクエストあたりの最大取得件数 default:30 max:150
mkt = "ja-JP"   # 取得元の国コード
 
num_per = 2   # リクエスト回数(count * num_per=取得画像数)
offset = math.floor(count / num_per)    # ループ回数
 
subscriptionKey="取得したキーを入力"    # Bing Search API Key
 
headers = {'Ocp-Apim-Subscription-Key':subscriptionKey}
 
for offset_num in range(offset):
    params = {'q':query,'count':count,'offset':offset_num*offset,'mkt':mkt}
    r = requests.get(url,headers=headers,params=params)
    data = r.json()
    for values in data['value']:
        image_url = values['contentUrl']
        try:
            download_img(path,image_url)
        except Exception as e:
            print("failed to download image at {}".format(image_url))
            print(e)
    time.sleep(1)

仮面ライダービルド 犬飼君の写っている画像を大量に集められました!

顔を抽出して保存する

次に、OpenCVを使って顔部分のみを抽出します。

# -*- coding:utf-8 -*-
import cv2
import numpy as np
import glob
#分類器のディレクトリ
HAAR_FILE = "haarcascade_frontalface_default.xml"
cascade = cv2.CascadeClassifier(HAAR_FILE)
#画像保存用のリスト
load_img_list = []
face_cut = []
count= 0
#出力画像のディレクトリパス
output_path = "./cutted_build_image/"
#加工元の画像ディレクトリパス
img_list = glob.glob("./build_image/*.jpg")

for img in img_list:
    load_img_list.append(cv2.imread(img))

for load_img in load_img_list:
    #顔の部分を識別(パラメータを変えることで精度を変えられます)
    face_rects = cascade.detectMultiScale(load_img,scaleFactor=1.1,minNeighbors=2,minSize=(100,100))
    print(face_rects)
    #顔が1つ以上検出されたら実行
    if(len(face_rects) !=0):        
        for face_rect in face_rects:
            x = face_rect[0]
            y = face_rect[1]
            w = face_rect[2]
            h = face_rect[3]
            #顔を切り出し
            face_cut = load_img[y:y + h, x:x + w]
            #画像リサイズ
            face_cut = cv2.resize(face_cut, dsize =(256, 256))
            #ファイル名を決定
            img_name = output_path + "build_build_" + str(count) + ".jpg"
            #画像書き込み
            cv2.imwrite(img_name, face_cut)
            count += 1
    else:pass
      

こちらも、マーカーの部分をご自身の設定に合わせて変更するだけで集めた画像の顔を抽出してくれます。

下のような感じで顔を抽出してくれます。

ですが、顔ではないところを切り抜いたり、他の人が混ざっていたりするのでここは手作業で取り除きます。

犬飼君のみ残るように他の画像を手動で削除しました。万丈と戦兎が意外と似てて手こずりました(笑)

これを他の方の写真でも行います。(骨の折れる作業でした....)

集めてて思いましたが、やっぱり仮面ライダー俳優は総じてイケメンですね!!!

コマンドプロンプトで数を数えたいディレクトリに移動し、以下のコマンドを入力することで画像の数を数えることができます。

dir /w /s /a *.*
  • ゼロワン:124
  • ビルド:158
  • ジオウ:159

画像を訓練データとテストデータに分類

画像データを訓練・テストデータに分類していきます

import os
import shutil
import random


def image_dir_train_test_sprit(original_dir, base_dir, train_size=0.8):
    '''
    画像データをトレインデータとテストデータにシャッフルして分割します。フォルダもなければ作成します。

    parameter
    ------------
    original_dir: str
      オリジナルデータフォルダのパス その下に各クラスのフォルダがある
    base_dir: str
      分けたデータを格納するフォルダのパス そこにフォルダが作られます
    train_size: float
      トレインデータの割合
    '''
    try:
        os.mkdir(base_dir)
    except FileExistsError:
        print(base_dir + "は作成済み")

    #クラス分のフォルダ名の取得
    dir_lists = os.listdir(original_dir)
    dir_lists = [f for f in dir_lists if os.path.isdir(os.path.join(original_dir, f))]
    original_dir_path = [os.path.join(original_dir, p) for p in dir_lists]

    num_class = len(dir_lists)

    # フォルダの作成(train,validation)
    try:
        train_dir = os.path.join(base_dir, 'train')
        os.mkdir(train_dir)
    except FileExistsError:
        print(train_dir + "は作成済み")

    try:
        validation_dir = os.path.join(base_dir, 'validation')
        os.mkdir(validation_dir)
    except FileExistsError:
        print(validation_dir + "は作成済み")

    #クラスフォルダの作成
    train_dir_path_lists = []
    val_dir_path_lists = []
    for D in dir_lists:
        train_class_dir_path = os.path.join(train_dir, D)
        try:
            os.mkdir(train_class_dir_path)
        except FileExistsError:
            print(train_class_dir_path + "は作成済み")
        train_dir_path_lists += [train_class_dir_path]
        val_class_dir_path = os.path.join(validation_dir, D)
        try:
            os.mkdir(val_class_dir_path)
        except FileExistsError:
            print(val_class_dir_path + "は作成済み")
        val_dir_path_lists += [val_class_dir_path]


    #元データをシャッフルしたものを上で作ったフォルダにコピーします。
    #ファイル名を取得してシャッフル
    for i,path in enumerate(original_dir_path):
        files_class = os.listdir(path)
        random.shuffle(files_class)
        # 分割地点のインデックスを取得
        num_bunkatu = int(len(files_class) * train_size)
        #トレインへファイルをコピー
        for fname in files_class[:num_bunkatu]:
            src = os.path.join(path, fname)
            dst = os.path.join(train_dir_path_lists[i], fname)
            shutil.copyfile(src, dst)
        #valへファイルをコピー
        for fname in files_class[num_bunkatu:]:
            src = os.path.join(path, fname)
            dst = os.path.join(val_dir_path_lists[i], fname)
            shutil.copyfile(src, dst)
        print(path + "コピー完了")

    print("分割終了")


def main():
    original_dir = "data"
    base_dir = "split_data"
    #何割訓練データにするか
    train_size = 0.8
    image_dir_train_test_sprit(original_dir, base_dir, train_size)


if __name__ == "__main__":
    main()

こんな感じできれいに分割される。

とりあえず今回はここまでにしたいと思います。後編では、ディープラーニングのモデルを構築していきます!

後編はこちら→【TensorFlow2入門】ディープラーニング(CNN)で仮面ライダー俳優を見分けるAIを作る(後編)

参考サイト

どのサイトもとても有益でした。ありがとうございます!

スポンサーリンク

-機械学習