Мне нужно сделать CNN, чтобы обнаружить диабетическую ретинопатию на 4-й стадии (он должен определить, есть ли DR на 4-й стадии или нет, не требует обнаружения других уровней). На входе будут такие изображения: https://i.imgur.com/DsU06Xv.jpg
Чтобы лучше классифицировать, я уточняю свое изображение: https://i.imgur.com/X1p9G1c.png
Итак, у меня есть база данных с 700 изображениями сетчаткина уровне 0 и 700 сетчатках с уровнем 4.
Проблема в том, что все модели, которые я пытался сделать, не работают, как правило, это стало проблемой переоснащения ..
Я уже пытался использоватьПоследовательная модель, Функциональный API ... и в одном из моих вопросов пользователь рекомендовал мне использовать VGG16 >> вопрос: https://datascience.stackexchange.com/questions/60706/how-do-i-handle-with-my-keras-cnn-overfitting
А сейчас я пытаюсь использовать VGG16, но все еще не работает. не работает, все мои прогнозы равны 0 , и я понятия не имею, что с этим делать ..
Это мой поезд.py:
import cv2
import os
import numpy as np
from keras.layers.core import Flatten, Dense, Dropout, Reshape
from keras.layers.normalization import BatchNormalization
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D
from keras import regularizers
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.models import Sequential
from keras.utils import to_categorical
from keras.applications.vgg16 import VGG16
# example of using a pre-trained model as a classifier
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.applications.vgg16 import preprocess_input
from keras.applications.vgg16 import decode_predictions
TRAIN_DIR = 'train/'
TEST_DIR = 'test/'
v = 'v/'
BATCH_SIZE = 32
NUM_EPOCHS = 5
def ReadImages(Path):
LabelList = list()
ImageCV = list()
classes = ["nonPdr", "pdr"]
# Get all subdirectories
FolderList = [f for f in os.listdir(Path) if not f.startswith('.')]
# Loop over each directory
for File in FolderList:
for index, Image in enumerate(os.listdir(os.path.join(Path, File))):
# Convert the path into a file
ImageCV.append(cv2.resize(cv2.imread(os.path.join(Path, File) + os.path.sep + Image), (224,224)))
#ImageCV[index]= np.array(ImageCV[index]) / 255.0
LabelList.append(classes.index(os.path.splitext(File)[0]))
ImageCV[index] = cv2.addWeighted(ImageCV[index],4, cv2.GaussianBlur(ImageCV[index],(0,0), 224/30), -4, 128)
return ImageCV, LabelList
data, labels = ReadImages(TRAIN_DIR)
valid, vlabels = ReadImages(TEST_DIR)
vgg16_model = VGG16(weights="imagenet", include_top=True)
# (1) 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("block5_pool").output)
# (3) attach a new top layer
base_out = base_model.output
base_out = Reshape((25088,))(base_out)
top_fc1 = Dropout(0.5)(base_out)
# output layer: (None, 5)
top_preds = Dense(1, activation="sigmoid")(top_fc1)
# (4) freeze weights until the last but one convolution layer (block4_pool)
for layer in base_model.layers[0:14]:
layer.trainable = False
# (5) create new hybrid model
model = Model(input=base_model.input, output=top_preds)
# (6) compile and train the model
sgd = SGD(lr=1e-4, momentum=0.9)
model.compile(optimizer=sgd, loss="binary_crossentropy", metrics=["accuracy"])
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)
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(data)
# fits the model on batches with real-time data augmentation:
model.fit_generator(datagen.flow(np.array(data), np.array(labels), batch_size=32),
steps_per_epoch=len(np.array(data)) / 32, epochs=5)
#history = model.fit([data], [labels], nb_epoch=NUM_EPOCHS,
# batch_size=BATCH_SIZE, validation_split=0.1)
# evaluate final model
#vlabels = model.predict(np.array(valid))
model.save('model.h5')
Когда я запускаю его, возвращает точность ~ 1,0 или 0,99% с минимальными потерями ~ 0,01 ..
Это мой предикат.py:
from keras.models import load_model
import cv2
import os
import json
import h5py
import numpy as np
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
TEST_DIR = 'v/'
def fix_layer0(filename, batch_input_shape, dtype):
with h5py.File(filename, 'r+') as f:
model_config = json.loads(f.attrs['model_config'].decode('utf-8'))
layer0 = model_config['config']['layers'][0]['config']
layer0['batch_input_shape'] = batch_input_shape
layer0['dtype'] = dtype
f.attrs['model_config'] = json.dumps(model_config).encode('utf-8')
fix_layer0('model.h5', [None, 224, 224, 3], 'float32')
model = load_model('model.h5')
for filename in os.listdir(r'v/'):
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))
x = image.img_to_array(ImageCV)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
print(np.argmax(model.predict(x)))
Когда я его запускаю, всемои прогнозы равны 0 .. и если отбросить np.argmax и запустить только model.predict, возвращает следующий результат:
[[0.03993018]]
[[0.9984968]]
[[1.]]
[[1.]]
[[0.]]
[[0.9999999]]
[[0.8691623]]
[[1.01611796e-07]]
[[1.]]
[[0.]]
[[1.]]
[[0.17786741]]
Учитывая, что 2 first изображения - класс 0, а остальные - класс 1 (уровень 4), результаты не 0.99 или 1.0 соотв. ..
Что я должен сделать? Я очень, очень ценю любую помощь!
ОБНОВЛЕНИЕ
Я обновил свой код, как сказал @Manoj .. Я добавил проверку и досрочное прекращение:
es = EarlyStopping(monitor='val_loss', verbose=1)
# fits the model on batches with real-time data augmentation:
model.fit_generator(datagen.flow(np.array(data), np.array(labels), batch_size=32),
steps_per_epoch=len(np.array(data)) / 32, epochs=5,
validation_data=(np.array(valid), np.array(vlabels)),
nb_val_samples=72, callbacks=[es])
И возвращает эти числа:
Epoch 1/5
44/43 [==============================] - 452s 10s/step - loss: 0.2377 - acc: 0.9162 - val_loss: 1.9521 - val_acc: 0.8472
Epoch 2/5
44/43 [==============================] - 445s 10s/step - loss: 0.0229 - acc: 0.9991 - val_loss: 1.8908 - val_acc: 0.8611
Epoch 3/5
44/43 [==============================] - 447s 10s/step - loss: 0.0107 - acc: 0.9993 - val_loss: 1.7658 - val_acc: 0.8611
Epoch 4/5
44/43 [==============================] - 458s 10s/step - loss: 0.0090 - acc: 0.9993 - val_loss: 1.6805 - val_acc: 0.8750
Epoch 5/5
44/43 [==============================] - 463s 11s/step - loss: 0.0052 - acc: 0.9993 - val_loss: 1.6730 - val_acc: 0.8750
Но после этого мои прогнозы (которые были верны 7/12) теперь верны 5/12 ..
Что я могу сделать, чтобы справиться с этим?
ОБНОВЛЕНИЕ 2
Я поместил этот код в мой train.py:
mean = datagen.mean
std = datagen.std
print(mean, "mean")
print(std, "std")
и значения, возвращаемые этими отпечатками, которые я вставил в Forex.py:
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
for filename in os.listdir(r'v/'):
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))
x = image.img_to_array(ImageCV)
x = np.expand_dims(x, axis=0)
x = normalize(x, [59.5105,61.141457,61.141457], [60.26705,61.85445,63.139835])
prob = model.predict(x)
if prob < 0.5:
print("nonPDR")
else:
print("PDR")
print(filename)
и теперь все мои прогнозы - (класс 1) PDR ... Я сделал что-то не так?
ОБНОВЛЕНИЕ 3
Я выпалgaussianblur, который я использовал в ReadImages, и включал следующее:
data = np.asarray(data)
valid = np.asarray(valid)
data = data.astype('float32')
valid = valid.astype('float32')
data /= 255
valid /= 255
И после запуска мой train.py:
Epoch 1/15
44/43 [==============================] - 476s 11s/step - loss: 0.7153 - acc: 0.5788 - val_loss: 0.6937 - val_acc: 0.5556
Epoch 2/15
44/43 [==============================] - 468s 11s/step - loss: 0.5526 - acc: 0.7275 - val_loss: 0.6838 - val_acc: 0.5833
Epoch 3/15
44/43 [==============================] - 474s 11s/step - loss: 0.5068 - acc: 0.7595 - val_loss: 0.6927 - val_acc: 0.5694
Epoch 00003: early stopping
После того, как я обновляю стандартное значение и среднее значение на Forex.py:
for filename in os.listdir(r'v/'):
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))
ImageCV = np.asarray(ImageCV)
ImageCV = ImageCV.astype('float32')
ImageCV /= 255
x = ImageCV
x = np.expand_dims(x, axis=0)
x = normalize(x, [0.12810835, 0.17897758, 0.23883381], [0.14304605, 0.18229756, 0.2362126])
prob = model.predict(x)
if prob <= 0.70: # I CHANGE THE THRESHOLD TO 0.7
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)
И после запуска этого кода я получаю примерно 75% точности в моем тестовом каталоге.
Итак, я могу что-то улучшить, или это максимум для этихкрошечное число яМаги