凯拉斯,Python。高精度模型总是分类错误

Posted

技术标签:

【中文标题】凯拉斯,Python。高精度模型总是分类错误【英文标题】:Keras, Python. High accuracy model classifies incorrectly all the time 【发布时间】:2017-08-17 14:02:35 【问题描述】:

我有 2 节课。 0=狗,1=非狗。 8800 张图像(150,150 像素)用于训练,4400 张图像用于验证。 4400 只狗,4400 只非狗在训练。 2200 只狗,2200 只非狗在验证中。 非狗图像包含船、树、钢琴等的随机图像。 我已经将我的网络训练到了 87% 以上的准确率。 情节: AccvsValAcc - http://imgur.com/a/6y6DG 损失VSValLoss - http://imgur.com/a/QGZQx

我的网络:

#model dog/nondog
model = Sequential()
model.add(Convolution2D(16, 3, 3, input_shape=(3, img_width, img_height)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(16, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

据我所知,我在模型末尾有 1 个节点,如果我只需要从非狗中分类狗,我会处理二进制分类问题。

我面临的问题是当我model.predict 一张看不见的狗图片到系统时,它总是将其归类为非狗。我是否错误地处理了这个问题?如果我的准确性如此之高,谁能向我解释为什么它从不将狗图片归类为狗?您可以向我的网络或方法推荐任何更改吗?

编辑: 最初我在 70x70 图像上进行了训练。刚刚完成了 150x150 图像的再训练。也代替 model.predict 我现在使用 model.predict_classes。但它仍然是同样的问题。结果始终是我尝试的每张图像的非狗结果。 :(

EDIT2:完整代码:

    # -*- coding: utf-8 -*-
"""
Created on Thu Jan 26 16:21:36 2017

@author: PoLL
"""

from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

from PIL import Image
import numpy as np

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import PIL
from PIL import Image
#draw rect
import matplotlib.patches as patches






#########################################################################################################
#VALUES
# dimensions of images.
img_width, img_height = 150,150
train_data_dir = 'data1/train'
validation_data_dir = 'data1/validation'
nb_train_samples = 8800 #1000 cats/dogs
nb_validation_samples = 4400 #400cats/dogs
nb_epoch = 20
#########################################################################################################


#model dog/nondog
model = Sequential()
model.add(Convolution2D(16, 3, 3, input_shape=(3, img_width, img_height)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(16, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])








#augmentation configuration for training
train_datagen = ImageDataGenerator(
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)
############################################################################################
#PRINT MODEL
from keras.utils.visualize_util import plot
plot(model, to_file='C:\Users\PoLL\Documents\Python Scripts\catdog\model.png')  
##########################################################################################################
#TEST AUGMENTATION
img = load_img('data/train/cats/cat.0.jpg')  # this is a PIL image
x = img_to_array(img)  # this is a Numpy array with shape (3, 150, 150)
x = x.reshape((1,) + x.shape)  # this is a Numpy array with shape (1, 3, 150, 150)

# the .flow() command below generates batches of randomly transformed images
# and saves the results to the `preview/` directory
i = 0
for batch in train_datagen.flow(x, batch_size=1,
                          save_to_dir='data/TEST AUGMENTATION', save_prefix='cat', save_format='jpeg'):
    i += 1
    if i > 20:
        break  # otherwise the generator would loop indefinitely
##########################################################################################################

# only rescaling
test_datagen = ImageDataGenerator(rescale=1./255)

#PREPARE TRAINING DATA
train_generator = train_datagen.flow_from_directory(
        train_data_dir, #data/train
        target_size=(img_width, img_height),  #RESIZE to 150/150
        batch_size=32,
        class_mode='binary')  #since we are using binarycrosentropy need binary labels

#PREPARE VALIDATION DATA
validation_generator = test_datagen.flow_from_directory(
        validation_data_dir,  #data/validation
        target_size=(img_width, img_height), #RESIZE 150/150
        batch_size=32,
        class_mode='binary')


#START model.fit
history =model.fit_generator(
        train_generator, #train data
        samples_per_epoch=nb_train_samples,
        nb_epoch=nb_epoch,
        validation_data=validation_generator,  #validation data
        nb_val_samples=nb_validation_samples)

############################################################################################
#LOAD WEIGHTS
model.load_weights('savedweights2.h5')
############################################################################################
#check labels 0=cat 1=dog
#dog = 0, nondog =1
labels = (train_generator.class_indices)
print(labels)
############################################################################################
#TESTING
#load test DOG
img=load_img('data/prediction/catordog/dog.1234.jpg')
#reshape to 1,3,150,150
img = np.array(img).reshape((1,3,img_width, img_height))
plt.imshow(img.reshape((150, 150, 3)))
print(model.predict_classes(img))
#load test CAT
img2=load_img('data/prediction/catordog/cat.187.jpg')
#reshape to 1,3,150,150
img2 = np.array(img2).reshape((1,3,img_width, img_height))
plt.imshow(img2.reshape((150, 150, 3)))
print(model.predict_classes(img))
print(model.predict_classes(img2))


############################################################################################
#RESIZE IMAGES
baseheight = 70
basewidth = 70
img = Image.open('data/prediction/catordog/dog.1297.jpg')
wpercent = (basewidth / float(img.size[0]))
hsize = int((float(img.size[1]) * float(wpercent)))
img = img.resize((basewidth, hsize), PIL.Image.ANTIALIAS)
img.save('resized_dog.jpg')
############################################################################################

#load test DOG
img=load_img('resized_dog.jpg')
#reshape to 1,3,150,150
img = np.array(img).reshape((1,3,img_width, img_height))
plt.imshow(img.reshape((70, 70, 3)))

print(model.predict(img))

#plt.imshow(image)
print(img.shape)
############################################################################################
##### WINDOW BOX  TO GO THROUGH THIS IMAGE
image=load_img('finddog/findadog2.jpg')
image= np.array(image).reshape((600,1050,3))
plt.imshow(image)
print(image.shape)

############################################################################################
############################################################################################
#OBJECT IS HERE

#object x,y,w,h,
object0 =  (140, 140, 150,150)
object1 =  (340, 340, 150,150)
#object2 = (130,130,150,150)
objloc  = []
objloc.append(object0)
objloc.append(object1)
#objloc.append(object2)



#SLIDING WINDOW
def find_a_dog(image, step=20, window_sizes=[70]):
    boxCATDOG = 0  
    locations = []
    for win_size in window_sizes:
        #top =y, left =x
        for Y in range(0, image.shape[0] - win_size + 1, step):
            for X in range(0, image.shape[1] - win_size + 1, step):
                # compute the (top, left, bottom, right) of the bounding box
                box = (Y, X, Y + win_size, X + win_size)
                # crop
                cropped_img = image[box[0]:box[2], box[1]:box[3]]
                #reshape cropped image by window
                cropped_img = np.array(cropped_img).reshape((1,3,70,70))
                #classify it
                boxCATDOG = predict_function(cropped_img)              
                if boxCATDOG ==0:
                 #   print('box classified as dog') 
                    #save location of it                 
                    locations.append(box)
                    print("found dog")
    return locations                                 



############################################################################################                   
#FUNCTIONS   #
def predict_function(x):
    result = model.predict_classes(x)
    if result==1:
        return 1
    else:
        return 0   
#SHOW CROPPED IMAGE
def show_image(im):
   plt.imshow(im.reshape((150,150,3)))
#SHOW INPUT IMAGE
def show_ori_image(im):
   plt.imshow(im.reshape((600,1050,3)))

def draw_obj_loc(image,objectloc):
    fix,ax = plt.subplots(1)
    ax.imshow(image)
    for l in objloc:
        rectG = patches.Rectangle((l[0],l[1]),l[2],l[3],linewidth=1,edgecolor='G',facecolor='none')
        ax.add_patch(rectG)
    print len(objectloc)

    #draw box when classifies as dog
def draw_boxes(image, locations):
    fix,ax = plt.subplots(1)
    ax.imshow(image)       
    for l in locations:
        print l
        rectR = patches.Rectangle((l[1],l[0]),150,150,linewidth=1,edgecolor='R',facecolor='none')
        ax.add_patch(rectR)
    print len(locations)

def draw_both(image, locations,objectloc):
    fix,ax = plt.subplots(1)
    ax.imshow(image)
    for l in objloc:
        rectG = patches.Rectangle((l[0],l[1]),l[2],l[3],linewidth=1,edgecolor='G',facecolor='none')
        ax.add_patch(rectG)
    for l in locations:
        print l
        rectR = patches.Rectangle((l[1],l[0]),150,150,linewidth=1,edgecolor='R',facecolor='none')
        ax.add_patch(rectR)
#check if overlaps
def check_overlapping(image,locations,objloc):   

    for ol in objloc:
        objX = (ol[0])
        objY = (ol[1])
        objW = (ol[2])
        objH = (ol[3])

        for ok in locations:
            X=(ok[0])
            Y=(ok[1])
   # for l in locations:
        #  if (objX+objW<X or X+150<objX or objY+objH<Y or Y+150<objY):
            if (objX+objW<X or X+150<objX or objY+objH<Y or Y+150<objY):
                # Intersection = Empty
                       #no overlapping, false positive
                       print('THERES NO OVERLAPPING :',objloc.index(ol))
                        #                                              
            else:
                        #Intersection = Not Empty
                        print('THERE IS OVERLAPPING WITH OBJECT: ',objloc.index(ol), 'WITH BOX NUMBER: ',locations.index(ok))



############################################################################################       
#get locations from image
locations = find_a_dog(image)
#show where windowslide classifed as positive
draw_boxes(image,locations)
#show where objects actually are
draw_obj_loc(image,objloc)
#check for overlapping between slider classification and actual
check_overlapping(image,locations,objloc)
#drawboth boxes
draw_both(image, locations,objloc)







#GREEN RECT
#   X,Y    X+W,Y
      ######
      #    #
      #    #
      ######
#   X,Y+H   X+W,Y+H


#WINDOW
#  Y1,X1   Y1+W,X1
      ######
      #    #
      #    #
      ######
# Y1,X+H   Y1+W,X1+H

###REMOVED FUNCTIONS
##DRAW RECT RED
def draw_rect(im,Y,X):
    fig,ax = plt.subplots(1)
    ax.imshow(im)
    rect = patches.Rectangle((Y,X),150,150,linewidth=1,edgecolor='r',facecolor='none')
    ax.add_patch(rect) 
   # im =plt.savefig('rect.jpg')

######OBJECT LOCATION AND H W GREEN
def draw_box_object(im,X,Y,W,H):
    fig,ax = plt.subplots(1)
    ax.imshow(im)
    rect = patches.Rectangle((X,Y),W,H,linewidth=1,edgecolor='G',facecolor='none')
    ax.add_patch(rect)
  #  im = plt.savefig('boxfordog.jpg')


################################################################################################
#PLOT
#ACC VS VAL_ACC
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy ACC VS VAL_ACC')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
#LOSS VS VAL_LOSS
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss LOSS vs VAL_LOSS')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
################################################################################################
#SAVE WEIGHTS
model.save_weights('savedweights.h5')
#70x70
model.save_weights('savedweights2.h5')
#150x150
model.save_weights('savedweights3.h5')

我为混乱的代码道歉,经常发生很多变化..

【问题讨论】:

训练集中狗与非狗的比例是多少? 4400 条狗,4400 条非狗。 1:1 您是否进行了任何预处理?很容易忘记以与预处理训练输入(和验证)相同的方式(完全相同)预处理新输入。 我指的是通常的预处理,例如用数据集的平均值减去每个通道,然后除以它的偏差。你能提供完整的代码吗? 您的预处理似乎是将整个图像除以 255。您能否在预测之前在测试图像中应用相同的除法? 【参考方案1】:

您在哪个数据集上测量准确性?我建议使用学习曲线和其他性能指标虱精度和召回率执行“机器学习诊断”,这将帮助您确定您是否正在遭受过度拟合并为您提供一些指导。

还要进行“错误分析”,举一些你的模型出错的例子,看看其中是否有任何模式。

【讨论】:

以上是关于凯拉斯,Python。高精度模型总是分类错误的主要内容,如果未能解决你的问题,请参考以下文章

Python混淆矩阵中的模型精度为0%

模型评估与选择

PaddlePaddle迁移学习做图像分类,数十种高精度模型任意切换

精度随着时代的增加而降低

如何提高机器学习的分类精度

模型的度量