在我的 CNN 中,我必须在二进制系统中处理 2 个类,每个类有 700 个图像要训练,其他的要验证。这是我的 train.py:
#import tensorflow as tf
import cv2
import os
import numpy as np
from keras.layers.core import Flatten, Dense, Dropout, Reshape
from keras.models import Model
from keras.layers import Input, ZeroPadding2D, Dropout
from keras import optimizers
from keras.optimizers import SGD
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import EarlyStopping
from keras.applications.vgg16 import VGG16
TRAIN_DIR = 'train/'
TEST_DIR = 'test/'
v = 'v/'
BATCH_SIZE = 32
NUM_EPOCHS = 5
def crop_img(img, h, w):
h_margin = (img.shape[0] - h) // 2 if img.shape[0] > h else 0
w_margin = (img.shape[1] - w) // 2 if img.shape[1] > w else 0
crop_img = img[h_margin:h + h_margin,w_margin:w + w_margin,:]
return crop_img
def subtract_gaussian_blur(img):
return cv2.addWeighted(img, 4, cv2.GaussianBlur(img, (0, 0), 5), -4, 128)
def ReadImages(Path):
LabelList = list()
ImageCV = list()
classes = ["nonPdr", "pdr"]
FolderList = [f for f in os.listdir(Path) if not f.startswith('.')]
for File in FolderList:
for index, Image in enumerate(os.listdir(os.path.join(Path, File))):
ImageCV.append(cv2.resize(cv2.imread(os.path.join(Path, File) + os.path.sep + Image), (224,224)))
LabelList.append(classes.index(os.path.splitext(File)[0]))
img_crop = crop_img(ImageCV[index].copy(), 224, 224)
ImageCV[index] = subtract_gaussian_blur(img_crop.copy())
return ImageCV, LabelList
data, labels = ReadImages(TRAIN_DIR)
valid, vlabels = ReadImages(TEST_DIR)
vgg16_model = VGG16(weights="imagenet", include_top=True)
base_model = Model(input=vgg16_model.input,
output=vgg16_model.get_layer("block5_pool").output)
base_out = base_model.output
base_out = Reshape((25088,))(base_out)
top_fc1 = Dense(4096, activation="relu")(base_out)
top_fc1 = Dropout(0.5)(base_out)
top_fc1 = Dense(4096, activation="relu")(base_out)
top_fc1 = Dropout(0.5)(base_out)
top_fc1 = Dense(64, activation="relu")(base_out)
top_fc1 = Dropout(0.5)(base_out)
top_preds = Dense(1, activation="sigmoid")(top_fc1)
for layer in base_model.layers[0:14]:
layer.trainable = False
model = Model(input=base_model.input, output=top_preds)
sgd = SGD(lr=1e-4, momentum=0.9)
model.compile(optimizer=sgd, loss="binary_crossentropy", metrics=["accuracy"])
data = np.asarray(data)
valid = np.asarray(valid)
data = data.astype('float32')
valid = valid.astype('float32')
data /= 255
valid /= 255
labels = np.array(labels)
perm = np.random.permutation(len(data))
data = data[perm]
labels = labels[perm]
datagen = ImageDataGenerator(
featurewise_center=True,
featurewise_std_normalization=True,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True)
datagen.fit(data)
mean = datagen.mean #This result I put manually in predict.py
std = datagen.std #This result I put manually in predict.py
print(mean, "mean")
print(std, "std")
es = EarlyStopping(monitor='val_loss', verbose=1)
model.fit_generator(datagen.flow(data, np.array(labels), batch_size=32),
steps_per_epoch=len(data) / 32, epochs=15,
validation_data=(valid, np.array(vlabels)),
nb_val_samples=72, callbacks=[es])
model.save('model.h5')
在运行这段代码之后,它会在 5 或 6 个 epoch 后返回一个大约 100% 准确率的奇怪结果。所以我尝试运行我的 predict.py 代码:(我知道我必须封装一些方法,但现在我只是从 train 复制并粘贴所有内容)
from keras.models import load_model
import cv2
import os
import numpy as np
TEST_DIR = 'v/0/'
pdr = 0
nonPdr = 0
model = load_model('model.h5')
def normalize(x, mean, std):
x[..., 0] -= mean[0]
x[..., 1] -= mean[1]
x[..., 2] -= mean[2]
x[..., 0] /= std[0]
x[..., 1] /= std[1]
x[..., 2] /= std[2]
return x
def crop_img(img, h, w):
h_margin = (img.shape[0] - h) // 2 if img.shape[0] > h else 0
w_margin = (img.shape[1] - w) // 2 if img.shape[1] > w else 0
crop_img = img[h_margin:h + h_margin,w_margin:w + w_margin,:]
return crop_img
def subtract_gaussian_blur(img):
return cv2.addWeighted(img, 4, cv2.GaussianBlur(img, (0, 0), 5), -4, 128)
for filename in os.listdir(r'v/0/'):
if filename.endswith(".jpg") or filename.endswith(".ppm") or filename.endswith(".jpeg") or filename.endswith(".png"):
ImageCV = cv2.resize(cv2.imread(os.path.join(TEST_DIR) + filename), (224,224))
img_crop = crop_img(ImageCV.copy(), 224, 224)
ImageCV = subtract_gaussian_blur(img_crop.copy())
ImageCV = np.asarray(ImageCV)
ImageCV = ImageCV.astype('float32')
ImageCV /= 255
ImageCV = np.expand_dims(ImageCV, axis=0)
ImageCV = normalize(ImageCV, [0.23883381, 0.23883381, 0.23883381], [0.20992693, 0.25749, 0.26330808]) #Values from train
prob = model.predict(ImageCV)
if prob <= 0.75: #.75 = 80% | .70=79% >>>> .70 = 82% | .75 = 79%
print("nonPDR >>>", filename)
nonPdr += 1
else:
print("PDR >>>", filename)
pdr += 1
print(prob)
print("Number of retinas with PDR: ",pdr)
print("Number of retinas without PDR: ",nonPdr)
问题是:当我尝试预测时,我几乎所有的预测都很差(对所有图像的预测都是 nonPdr 或 0 类)。我已经尝试切断数据增强进行测试,结果并没有改变我想要的方式。我也尝试改变我的模型,改变预处理(这个预处理是我可以用于这个项目的最好的)并且永远不会发生。
我该如何处理?
更新
正如@serali 所说,我试图削减一些层以减少过度拟合。这是我现在的模型:
vgg16_model = VGG16(weights="imagenet", include_top=True)
#visualize layers
print("VGG16 model layers")
for i, layer in enumerate(vgg16_model.layers):
print(i, layer.name, layer.output_shape)
# (2) remove the top layer
base_model = Model(input=vgg16_model.input,
output=vgg16_model.get_layer("block1_pool").output)
# (3) attach a new top layer
base_out = base_model.output
top_fc1 = GlobalAveragePooling2D()(base_out)
top_fc2 = Dense(16, activation='relu')(top_fc1)
top_fc3 = Dropout(0.5)(top_fc2)
top_preds = Dense(1, activation="sigmoid")(top_fc3)
# (5) create new hybrid model
model = Model(input=base_model.input, output=top_preds)
如您所见,我切入了第一个卷积块,因此我的模型如下所示:
0 input_1 (None, 224, 224, 3)
1 block1_conv1 (None, 224, 224, 64)
2 block1_conv2 (None, 224, 224, 64)
3 block1_pool (None, 112, 112, 64)
top_fc1 = GlobalAveragePooling2D()(base_out)
top_fc2 = Dense(16, activation='relu')(top_fc1)
top_fc3 = Dropout(0.5)(top_fc2)
top_preds = Dense(1, activation="sigmoid")(top_fc3)
但是,当我尝试预测我训练过的相同图像时,预测是错误的(对于外国图像,结果是相同的)。那么,我该如何改进呢?