分类图像分类总是预测一个类,但计算精度达到100%

时间:2017-07-10 19:24:58

标签: keras-2

我遵循了Keras猫/狗图像分类教程 Keras Image Classification tutorial 并发现与报告值相似的结果。然后我从该教程Tutorial Example 1 code中的第一个示例中获取代码,略微改变了几行,并训练了模型以获得灰度图像数据集(7个类中约15万个图像)。

这给了我很好的初步结果(准确率达到84%),我很满意。

接下来我尝试自己实现图像批处理生成器,这是我遇到麻烦的地方。简而言之,代码似乎运行良好,除了报告的模型准确度在两个时期内快速射到> = 99%。由于数据集中的噪声,这种准确度是不可信的。在使用训练模型预测新一批数据(训练或验证数据集之外的图像)之后,我发现模型总是预测第一类(即[1.,0.,0.,0.,0。, 0.,。损失函数强制模型在100%的时间内预测单个类,即使我传入的标签分布在所有类中。

经过28个训练时期后,我看到以下输出:

320/320 [==============================] - 1114s - loss: 1.5820e-07 - categorical_accuracy: 1.0000 - sparse_categorical_accuracy: 0.0000e+00 - val_loss: 16.1181 - val_categorical_accuracy: 0.0000e+00 - val_sparse_categorical_accuracy: 0.0000e+00

当我从教程代码中检查批处理生成器输出并比较我的批生成器输出时,两个生成器之间的形状,数据类型和值范围是相同的。 我想强调的是,生成器传递来自每个类别的y标签,而不仅仅是数组([1 ..,0.,0.,0.,0.,0.,0。],dtype = float32) 即可。因此,我迷失了我的错误。

自从我几天前发布此代码以来,我使用了默认的Keras图像生成器,并成功地在相同的数据集和相同的网络架构上训练了网络。因此,关于如何在生成器中加载和传递数据的某些内容必须是错误的。

以下是我实施的代码:

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.optimizers import SGD
from keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau
import imgaug as ia
from imgaug import augmenters as iaa
import numpy as np
import numpy.random as nprand
import imageio
import os, re, random, sys, csv
import scipy

img_width, img_height = 112, 112
input_shape = (img_width,img_height,1)
batch_size = 200
epochs = 2

train_image_directory = '/PATH/To/Directory/train/'
valid_image_directory = '/PATH/To/Directory/validate/'
video_info_file = '/PATH/To/Directory/train_labels.csv'
train_image_paths = [train_image_directory + m.group(1) for m in [re.match(r"(\d+_\d+\.png)", fname) for fname in os.listdir(train_image_directory)] if m is not None]
valid_image_paths = [valid_image_directory + m.group(1) for m in [re.match(r"(\d+_\d+\.png)", fname) for fname in os.listdir(valid_image_directory)] if m is not None]

num_train_images = len(train_image_paths)
num_val_images = len(valid_image_paths)
label_map = {}
label_decode = {
        '0': [1.,0.,0.,0.,0.,0.,0.],
        '1': [0.,1.,0.,0.,0.,0.,0.],
        '2': [0.,0.,1.,0.,0.,0.,0.],
        '3': [0.,0.,0.,1.,0.,0.,0.],
        '4': [0.,0.,0.,0.,1.,0.,0.],
        '5': [0.,0.,0.,0.,0.,1.,0.],
        '6': [0.,0.,0.,0.,0.,0.,1.]
        }

with open(video_info_file) as f:
        reader = csv.reader(f)
        for row in reader:
                key = row[0]
                if key in label_map:
                        pass
                label_map[key] = label_decode[row[1]]

sometimes = lambda aug: iaa.Sometimes(0.5,aug)

seq = iaa.Sequential(
        [
        iaa.Fliplr(0.5),
        iaa.Flipud(0.2),
        sometimes(iaa.Crop(percent=(0, 0.1))),
        sometimes(iaa.Affine(
                scale={"x": (0.8, 1.2), "y": (0.8, 1.2)},
                translate_percent={"x": (-0.2, 0.2), "y": (-0.2, 0.2)},
                rotate=(-5, 5),
                shear=(-16, 16),
                order=[0, 1],
                cval=(0, 1),
                mode=ia.ALL
                )),
        iaa.SomeOf((0, 3),
                    [
                        sometimes(iaa.Superpixels(p_replace=(0, 0.40), n_segments=(20, 100))),

                        iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)),
                        iaa.Emboss(alpha=(0, 1.0), strength=(0, 1.0)),
                        iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.05*255)),
                        iaa.OneOf([
                            iaa.Dropout((0.01, 0.1)),
                            iaa.CoarseDropout((0.03, 0.15), size_percent=(0.02, 0.05)),
                        ]),
                        iaa.Invert(0.05),
                        iaa.Add((-10, 10)),
                        iaa.Multiply((0.5, 1.5), per_channel=0.5),
                        iaa.ContrastNormalization((0.5, 2.0)),
                        sometimes(iaa.ElasticTransformation(alpha=(0.5, 1.5), sigma=0.2)),
                        sometimes(iaa.PiecewiseAffine(scale=(0.01, 0.03))) # sometimes move parts of the image around
                    ],
                    random_order=True
                )
        ],
        random_order=True)


def image_data_generator(image_paths, labels, batch_size, training):
        while(1):
                image_paths = nprand.choice(image_paths, batch_size)
                X0 = np.asarray([imageio.imread(x) for x in image_paths])
                Y = np.asarray([labels[x] for x in image_paths],dtype=np.float32)
                if(training):
                        X = np.divide(np.expand_dims(seq.augment_images(X0)[:,:,:,0],axis=3),255.)
                else:
                        X = np.expand_dims(np.divide(X0[:,:,:,0],255.),axis=3)
                X = np.asarray(X,dtype=np.float32)
                yield X,Y

def predict_videos(model,video_paths):
        i=0
        predictions=[]
        while(i < len(video_paths)):
                video_reader = imageio.get_reader(video_paths[i])
                X0 = np.expand_dims([ im[:,:,0] for x,im in enumerate(video_reader) ],axis=3)
                prediction = model.predict(X0)
                i=i+1
                predictions.append(prediction)
        return predictions

train_gen = image_data_generator(train_image_paths,label_map,batch_size,True)
val_gen = image_data_generator(valid_image_paths,label_map,batch_size,False)

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.4))
model.add(Dense(7))
model.add(Activation('softmax'))

model.load_weights('/PATH/To_pretrained_weights/pretrained_model.h5')

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy',
              optimizer='sgd',
              metrics=['categorical_accuracy','sparse_categorical_accuracy'])

checkpointer = ModelCheckpoint('/PATH/To_pretrained_weights/pretrained_model.h5', monitor='val_loss', verbose=0, save_best_only=True, save_weights_only=False, mode='auto', period=1)
reduceLR = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=20, verbose=0, mode='auto', cooldown=0, min_lr=0)
early_stop = EarlyStopping(monitor='val_loss', patience=20, verbose=1)
callbacks_list = [checkpointer, early_stop, reduceLR]

model.fit_generator(
        train_gen,
        steps_per_epoch = -(-num_train_images // batch_size),
        epochs=epochs,
        validation_data=val_gen,
        validation_steps = -(-num_val_images // batch_size),
        callbacks=callbacks_list)

1 个答案:

答案 0 :(得分:0)

由于某些原因我无法完全确定,如果您没有为fit_generator函数提供每个时期步骤的准确数字或验证步骤,结果是准确度量报告和奇怪的梯度下降步骤报告不准确。

您可以使用Keras中的Train_on_batch函数代替fit生成器,或通过准确报告这些步骤数来解决此问题。