質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.55%

keras 画像認識時のエラー

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,495

atsuo

score 4

https://toxweblog.toxbe.com/2017/06/03/keras-face-learning/

現在こちらのブログを参考にさせていただき、kerasで乃木坂46の顔認証を行うシステムを作成しています。

前述させていただいたブログで公開されている、ソースコードとデーターセットほぼそのまま引用させていただいて、kerasで顔認証を試しているのですが、顔を切り出して予測する段階でうまく行かずに困っています。

 発生している問題・エラーメッセージ

Using TensorFlow backend.
line  0_the_others,0

line  akimoto,1

line  hashimoto,2

line  ikoma,3

line  ikuta,4

line  nishino,5

line  shiraishi,6

2018-10-16 10:38:44.454517: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
Traceback (most recent call last):
  File "prediction.py", line 58, in <module>
    main()
  File "prediction.py", line 49, in main
    preds = model.predict(imgarray, batch_size=imgarray.shape[0])
  File "/home/okamoto/.pyenv/versions/anaconda3-4.2.0/lib/python3.5/site-packages/keras/engine/training.py", line 1152, in predict
    x, _, _ = self._standardize_user_data(x)
  File "/home/okamoto/.pyenv/versions/anaconda3-4.2.0/lib/python3.5/site-packages/keras/engine/training.py", line 754, in _standardize_user_data
    exception_prefix='input')
  File "/home/okamoto/.pyenv/versions/anaconda3-4.2.0/lib/python3.5/site-packages/keras/engine/training_utils.py", line 126, in standardize_input_data
    'with shape ' + str(data_shape))
ValueError: Error when checking input: expected conv2d_1_input to have 4 dimensions, but got array with shape (0, 1)

 prediction.py

from keras.models import Sequential, load_model
from keras.preprocessing.image import load_img, img_to_array
import numpy as np

import argparse
import cv2
from PIL import Image

def faceDetectionFromPath(path, size):
    cvImg = cv2.imread(path)
    cascade_path = './haarcascade_frontalface_alt.xml'
    cascade = cv2.CascadeClassifier(cascade_path)
    facerect = cascade.detectMultiScale(cvImg, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
    faceData = []
    for rect in facerect:
        faceImg = cvImg[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
        resized = cv2.resize(faceImg,None, fx=float(size/faceImg.shape[0]),fy=float(size/faceImg.shape[1]))
        CV_im_RGB = resized[:, :, ::-1].copy()
        pilImg=Image.fromarray(CV_im_RGB)
        faceData.append(pilImg)

    return faceData

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model', '-m', default='.\\lib\\mymodel.h5', required=True)
    parser.add_argument('--testpath', '-t', default='.\\lib\\images\\shiraishi.jpg')
    args = parser.parse_args()

    num_classes = 7
    img_rows, img_cols = 128, 128

    ident = [""] * num_classes
    for line in open("whoiswho.txt", "r"):
        print("line ", line)
        dirname = line.split(",")[0]
        label = line.split(",")[1]
        ident[int(label)] = dirname

    model = load_model(args.model)
    faceImgs = faceDetectionFromPath(args.testpath, img_rows)
    imgarray = []
    for faceImg in faceImgs:
        faceImg.show()
        imgarray.append(img_to_array(faceImg))
    imgarray = np.array(imgarray) / 255.0
    imgarray.astype('float32')

    preds = model.predict(imgarray, batch_size=imgarray.shape[0])
    for pred in preds:
        predR = np.round(pred)
        for pre_i in np.arange(len(predR)):

            if predR[pre_i] == 1:
                print("he/she is {}".format(ident[pre_i]))

if __name__ == '__main__':
    main()

こちらのエラーに対して、原因や対処法がわかる方、ご教授いただければ幸いです。
乃木坂が好きでこちらを試させていただきましたが、プログラミング初心者の私には早すぎた段階だったのかもしれません(泣)

 ubuntu16-04

一応、私でもうまく動かせた画像を読み込む?コードと学習データを読み込み保存するコードも貼り付けておきますので、なにかわかる方がいらっしゃいましたら、ご享受くださいませ。

 load_images.py

import numpy as np
import glob
from keras.preprocessing.image import load_img, img_to_array
import re

def load_images_from_labelFolder(path, img_width, img_height, train_test_ratio=(9,1)):
    pathsAndLabels = []
    label_i = 0
    data_list = glob.glob(path + '/*')
    print('path', path+'//*')
    datatxt = open('whoiswho.txt' ,'w')
    print('data_list', data_list)
    for dataFolderName in data_list:
        pathsAndLabels.append([dataFolderName, label_i])
        pattern = r".*//(.*)" #pathが階層を色々含んでいるので、画像が入っているフォルダ名だけを取っている。
        matchOB = re.finditer(pattern, dataFolderName)
        directoryname = ""
        if matchOB:
            for a in matchOB:
                directoryname += a.groups()[0]
        datatxt.write(directoryname + "," + str(label_i) + "\n") # 誰が何番かテキストで保存しとく
        label_i = label_i + 1
    datatxt.close()
    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) # シャッフルする。

    train_x = []
    train_y = []
    for (imgpath, label) in allData: #kerasが提供しているpreprocessing.imageでは画像の前処理のメソッドがある。
        img = load_img(imgpath, target_size=(img_width,img_height)) # 画像を読み込む
        imgarry = img_to_array(img) # 画像ファイルを学習のためにarrayに変換する。
        train_x.append(imgarry)
        train_y.append(label)

    threshold = (train_test_ratio[0]*len(train_x))//(train_test_ratio[0]+train_test_ratio[1])
    test_x = np.array(train_x[threshold:])
    test_y = np.array(train_y[threshold:])
    train_x = np.array(train_x[:threshold])
    train_y = np.array(train_y[:threshold])

    return (train_x, train_y), (test_x, test_y)


if __name__ == '__main__':
    (train_x,train_y),(_,_) = load_images_from_labelFolder('/home/okamoto/lib/images', 128, 128)

print('train_x.shape:',train_x.shape)

 train.py

from __future__ import print_function
import keras
from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, BatchNormalization, ZeroPadding2D
from keras import backend as K
import argparse
from load_images import load_images_from_labelFolder

batch_size = 20
num_classes = 7
epoch = 30

img_rows, img_cols = 128, 128


parser = argparse.ArgumentParser()
parser.add_argument('--path', '-p', default='./images')
args = parser.parse_args()


(x_train, y_train), (x_test, y_test) = load_images_from_labelFolder(args.path,img_cols, img_rows, train_test_ratio=(6,1))

print('x_train', x_train)

if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 3)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 3)
    input_shape = (img_rows, img_cols, 3)

x_train = x_train.astype('float32')
x_test  = x_test.astype('float32')
x_train /= 255
x_test /= 255


# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

model = Sequential()

model.add(Conv2D(32, kernel_size=(3,3),
            activation='relu',
            input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(Dropout(0.2))

model.add(ZeroPadding2D(padding=(1, 1)))
model.add(Conv2D(96, kernel_size=(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(Dropout(0.2))

model.add(ZeroPadding2D(padding=(1, 1)))
model.add(Conv2D(96, kernel_size=(3,3)))
model.add(MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(Flatten())

model.add(Dense(units=1024, activation='relu'))
model.add(Dropout(rate=0.5))
model.add(Dense(units=num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,
                optimizer=keras.optimizers.Adam(),
                metrics=['accuracy'])

model.fit(x_train, y_train,
            batch_size=batch_size,
            epochs=epoch,
            verbose=0,
            validation_data=(x_test, y_test))

score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

model.save('mymodel.h5') # 学習済みモデルを保存
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tiitoi

    2018/10/16 12:13

    predict() 直前の imgarray.shape の値を print するとどうなっていますか?

    キャンセル

  • atsuo

    2018/10/16 12:53

    tiitoi様 if __name__ == '__main__':の直前にprint("imgarray.shape",imgarray.shape) を入れましたが、NameError: name 'imgarray' is not definedというエラーが出てしまいます・・・。

    キャンセル

  • atsuo

    2018/10/16 13:00

    t_obara様 たしかにその通りですね。回答していただくという立場にもかかわらず質問内容が明確でなかったことを反省します。ご指摘ありがとうございました。踏まえて質問内容を訂正させていただきましたのでもしよろしければご一緒に考えていただけると幸いです。

    キャンセル

回答 1

0

ValueError: Error when checking input: expected conv2d_1_input to have 4 dimensions, but got array with shape (0, 1)

got array with shape (0, 1) と出ているので、モデルに与えられた入力データがおかしいというエラーです。
画像の読み込みもしくは顔の検出ができていないのではないでしょうか?

あと、以下はおかしいと思います。dsize=(128, 128) のようにリサイズするサイズを指定するべきです。

cv2.resize(faceImg,None, fx=float(size/faceImg.shape[0]),fy=float(size/faceImg.shape[1]))

以下、確認したパスから画像を読み込み、顔を切り出してバッチで取得するコードです。

import os
import cv2
import matplotlib.pyplot as plt
import numpy as np
from keras.models import Sequential, load_model
from keras.preprocessing.image import load_img, img_to_array

class FaceExtractor:
    def __init__(self):
        assert os.path.isfile('./haarcascade_frontalface_alt.xml'), 'カスケード定義ファイルがない'
        self.detector = cv2.CascadeClassifier('./haarcascade_frontalface_alt.xml')

    def extract(self, path, size):
        # 画像を読み込む。
        img = cv2.imread(path)
        # 検出する。
        rects = self.detector.detectMultiScale(
            img, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
        # BGR -> RGB
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # 顔画像を切り出す。
        face_imgs = []
        for x, y, w, h in rects:
            face_img = img[y:y + h, x: x + w]
            face_img = cv2.resize(face_img, size)
            face_imgs.append(face_img)
        return np.array(face_imgs)

extractor = FaceExtractor()
face_imgs = extractor.extract('nogizaka.jpg', size=(128, 128))

print(face_imgs.shape)  # (7, 128, 128, 3)
fig, axes = plt.subplots(2, 3, figsize=(8, 5))
for ax, img in zip(axes.ravel(), face_imgs):
    ax.imshow(img)
    ax.axis('off')
plt.show()

イメージ説明
切り出し結果

あとここもおかしいです。
astype() は配列のコピーを作成し、型を変換して返す関数なので、
以下のようにしても、imgarray 自体の型は変わりません。

imgarray.astype('float32')

上記に記載したサンプルコードのあとに以下のようにすると、(7, 128, 128, 3) の float32 型 numpy 配列が得られるのでこの x を predict() に流してください。
バッチサイズは指定しなくていいです。

x = np.array(face_imgs) / 255.
x = x.astype(np.float32)
y_pred = model.predict(x)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.55%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る