【问题标题】:CNN does not perform well on simple image recognition problem of cats and dogsCNN 在简单的猫狗图像识别问题上表现不佳
【发布时间】:2020-03-08 14:31:14
【问题描述】:

我正在尝试实现一个 CNN 来对猫和狗的图像进行分类。在阅读了互联网上的几个示例后,我提出了以下解决方案。导入是:

from keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import Adam
from sklearn.model_selection import train_test_split
from keras.preprocessing.image import img_to_array
from keras.utils import to_categorical
from imutils import paths
import numpy as np
import random
import cv2
import os
from keras import backend as K
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Activation, Dense, Dropout
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
from tensorflow.keras.layers import Conv2D Flatten, MaxPooling2D, Dropout, BatchNormalization
from keras.regularizers import l2
from sklearn.model_selection import KFold
from sklearn.metrics import classification_report

我的 CNN 如下:

model = Sequential()
inputShape = (height, width, depth)
# if we are using "channels first", update the input shape
if K.image_data_format() == "channels_first":
  inputShape = (depth, height, width)

model.add(Conv2D(filters=96, kernel_size=(11,11), strides=(4,4), input_shape = inputShape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))
model.add(Conv2D(filters=256, kernel_size=(11,11), strides=(1,1), padding='valid'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))
model.add(Conv2D(filters=384, kernel_size=(3,3), strides=(1,1), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(filters=384, kernel_size=(3,3), strides=(1,1), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(filters=256, kernel_size=(3,3), strides=(1,1), padding='valid'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))
model.add(Flatten())
model.add(Dense(4096, input_shape=(224*224*3,)))
model.add(Activation('relu'))
model.add(Dropout(0.4))
model.add(Dense(4096))
model.add(Activation('relu'))
model.add(Dropout(0.4))
model.add(Dense(1000))
model.add(Activation('relu'))
model.add(Dropout(0.4))
model.add(Dense(num_classes))
model.add(Activation('softmax'))

高度和宽度等于 224,深度等于 3,因为我有 RGB 图像。要阅读图像,我使用以下代码。目录是test_animals/cats/和test_animals/dogs,分别是猫和狗,每个标签有1000张jpg图片。

data = []
labels = []
# grab the image paths and randomly shuffle them
imagePaths = sorted(list(paths.list_images('test_animals')))
random.seed(42)
random.shuffle(imagePaths)
for imagePath in imagePaths:
    # load the image, pre-process it, and store it in the data list
    image = cv2.imread(imagePath)
    image = cv2.resize(image, (img_width, img_height))
    image = img_to_array(image)
    data.append(image)
    # extract the class label from the image path and update the
    # labels list
    label = imagePath.split(os.path.sep)[-2]
    label = 1 if label == "dogs" else 0
    labels.append(label)

data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)

然后,我尝试通过执行以下操作来执行 10 倍交叉验证:

kf = KFold(n_splits=10, random_state=42, shuffle=True)
current_fold = 1
for train_index, test_index in kf.split(data):
    print(f'[INFO] Current fold: {current_fold}')
    trainX, testX = data[train_index], data[test_index]
    trainY, testY = labels[train_index], labels[test_index]
    # Reserve 20% of the samples for validation
    num_val_samples = 0 - int(len(trainX)*0.2)
    x_val = trainX[num_val_samples:]
    y_val = trainY[num_val_samples:]
    trainX = trainX[:num_val_samples]
    trainY = trainY[:num_val_samples]
    # convert the labels from integers to vectors
    trainY = to_categorical(trainY, num_classes=2)
    y_val = to_categorical(y_val, num_classes=2)
    aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,horizontal_flip=True, fill_mode="nearest")
    model = LeNet.build(width=img_width, height=img_height, depth=3, num_classes=2)
    opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
    model.compile(loss="binary_crossentropy", optimizer=opt,metrics=["accuracy"])
    H = model.fit(aug.flow(trainX, trainY, batch_size=BS),validation_data=(x_val, y_val), steps_per_epoch=len(trainX) // BS,epochs=EPOCHS, verbose=1)
    y_pred = model.predict(testX, batch_size=64, verbose=1)
    y_pred_bool = np.argmax(y_pred, axis=1)
    print(classification_report(testY, y_pred_bool))
    current_fold += 1

目前实验的参数是:

EPOCHS = 50
INIT_LR = 1e-3
BS = 10
img_width = 224
img_height = 224
num_classes = 2

我的解决方案的问题是它总是能达到大约 50% 的准确度。无论 epoch 的大小(我尝试了 10,25,50,100),准确性和损失都保持不变,有时会随着 epoch 的进行而下降。此外,我还尝试了添加/删除层/maxpooling/conv2D,但结果保持不变。当我将样本增加到每个标签 5000 个时,准确度会变得更低。难道我做错了什么?有没有关于它的解释?我可以做些什么来提高模型的准确性?

这是数据集的链接: https://drive.google.com/file/d/1baqbZar9ceYQidD_LaIFvoDWlB1QcyYA/view?usp=sharing

【问题讨论】:

  • 如果你要在输出中使用 softmax 激活,你应该使用分类(不是二进制)交叉熵作为损失函数。
  • 结果不变。即使我使用 sigmoid 而不是 softmax,结果也不会改变

标签: python tensorflow keras conv-neural-network


【解决方案1】:

我认为,

由于您使用的是 softmax 激活,因此损失应该是 'categorical_crossentropy' 试试这个

昨天我在数据集上工作,我必须对图像进行分类,我还通过旋转增强了数据,但似乎没有增强数据的准确性比增强后的准确性高

我不知道我犯了什么错误,但它发生了

【讨论】:

  • 正如我在问题下方的评论中提到的,当我使用 categorical_crossentropy 时也会发生同样的事情。另外,我在互联网的某个地方看到,当我们进行二元分类时,最好使用二元交叉熵。
  • 能否提供数据集链接....?我也可以试试……
  • 我更新了问题以包含指向数据集的链接。看问题的最后,你可以在那里找到。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 2020-10-03
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多