【发布时间】: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