Python 用于图像分类的CNN表现不佳

Python 用于图像分类的CNN表现不佳,python,keras,neural-network,conv-neural-network,Python,Keras,Neural Network,Conv Neural Network,我正在建立一个用于膝关节X光图像处理的CNN,但是在每次跑步的第7-8个历元之后,验证和训练的损失/准确度并不一致,过了一段时间,验证损失开始增加。我试图通过数据扩充来增加我的数据集。现在我想知道是图像的质量、我的实际架构还是我保存数据的方式。对于数据预处理,我将每个图像保存为numpy数组,然后将其写入pickle文件。我也不太确定如何确定层数和超参数,但我确实得到了其他CNN的指导。我不知道还能尝试什么。对于如何改进这一模式的建议,我将不胜感激 import matplotlib.pyplo

我正在建立一个用于膝关节X光图像处理的CNN,但是在每次跑步的第7-8个历元之后,验证和训练的损失/准确度并不一致,过了一段时间,验证损失开始增加。我试图通过数据扩充来增加我的数据集。现在我想知道是图像的质量、我的实际架构还是我保存数据的方式。对于数据预处理,我将每个图像保存为numpy数组,然后将其写入pickle文件。我也不太确定如何确定层数和超参数,但我确实得到了其他CNN的指导。我不知道还能尝试什么。对于如何改进这一模式的建议,我将不胜感激

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from matplotlib.pyplot import imshow
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
import numpy as np
import random as rd
import boto3
import tempfile
import os
import io
import pickle
import tensorflow as tf
import keras
from keras.utils import to_categorical
from keras import optimizers
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers import Input, InputLayer
from keras.models import Model
from keras.utils import to_categorical
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.pooling import GlobalMaxPooling2D
from keras.models import model_from_json
from keras.layers import MaxPool2D, InputLayer, BatchNormalization

s3_client = boto3.client('s3')
my_array2 = []
labels = []
labels2 = []

x_train = []
x_test = [] 
y_train = []
y_test = []

def load_data():
    # download without using disk
    global my_array2
    my_array_data2 = io.BytesIO()
    s3_client.download_fileobj('msckneeoadata', 'KneeKL224AllReduced.pkl', my_array_data2)
    my_array_data2.seek(0)
    my_array2 = pickle.load(my_array_data2)

def load_labels():
    for x in range(3000):
        labels.append(0)

    for x in range(3000):
        labels.append(1)

    for x in range(3000):
        labels.append(2)

    for x in range(3000):
        labels.append(3)

    for x in range(3000):
        labels.append(4)

def ShuffleData():
    global labels
    global my_array2
    my_array2, labels = shuffle(my_array2, labels, random_state=0)

def SplitData():
    # split into 80% for train and 20% for test
    global x_train 
    global x_test  
    global y_train
    global y_test 
    global my_array2
    x_train, x_test, y_train, y_test = train_test_split(my_array2, labels, test_size=0.20, random_state=0)

    x_train = np.array(x_train)
    y_train = np.array(y_train,dtype='uint8')
    x_test = np.array(x_test)
    y_test = np.array(y_test,dtype='uint8')
    
    #one-hot encode target column
    y_train = to_categorical(y_train)
    y_test = to_categorical(y_test)
    
    #train the model
    x_train = x_train.reshape(12000,224,224,1)
    x_test = x_test.reshape(3000,224,224,1)

    x_train = x_train.astype('float64')
    x_test = x_test.astype('float64')

    x_train/=255
    x_test/=255
def create_model():
    global x_train
    global x_test
    global y_train
    global y_test

    #create model
    model = Sequential()
    #add model layers


model.add(Conv2D(input_shape=(224,224,1),filters=64,kernel_size=(11,11),padding="same", `activation="relu",name="Conv1_1"))`           
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2), name="Pool1_1"))

model.add(Conv2D(filters=128,kernel_size=(7,7),padding="same", activation="relu",name="Conv2_1"))
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2), name="Pool2_1"))

model.add(Conv2D(filters=256,kernel_size=(5,5),padding="same", activation="relu",name="Conv3_1"))
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2), name="Pool3_1"))

model.add(Conv2D(filters=512,kernel_size=(3,3),padding="same", activation="relu",name="Conv4_1"))
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2), name="Pool4_1"))


model.add(Flatten())
model.add(Dense(units=1024,activation="relu"))
model.add(Dropout(0.1))
model.add(Dense(units=5, activation="softmax",name="fc6"))


#compile model using accuracy to measure model performance
from keras.optimizers import SGD
opt = SGD(lr=0.1)

model.compile(loss = "categorical_crossentropy", optimizer = 'adam',metrics=['accuracy'])
model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=15,batch_size=150)

# Evaluate the model on the test data using `evaluate`
print('\n# Evaluate on test data')
results = model.evaluate(x_test, y_test, batch_size=100)
print('test loss, test acc:', results)

def main():
    load_data()
    load_labels()
    ShuffleData()
    SplitData()
    create_model()
以下是此执行的结果:

我将首先调整内核大小,因为这是最突出的。其想法是在网络顶部创建一些简单的功能,并允许它们在数据沿着网络滴流时通过大量过滤器构建复杂度

model.add(Conv2D(input_shape=(224,224,1),filters=32,kernel_size=2,padding="same", `activation="relu",name="Conv1_1"))`           
model.add(MaxPooling2D(pool_size=2, name="Pool1_1"))

model.add(Conv2D(filters=64,kernel_size=2,padding="same", activation="relu",name="Conv2_1"))
model.add(MaxPooling2D(pool_size=2, name="Pool2_1"))

model.add(Conv2D(filters=128,kernel_size=2,padding="same", activation="relu",name="Conv3_1"))
model.add(MaxPooling2D(pool_size=2, name="Pool3_1"))
您甚至可以删除一个卷积层,然后尝试3个

其他想法:

  • 尝试在卷积之间添加BatchNormalization
  • 尝试在卷积之间添加衰减(我将使用SpatialDropout2D)
我还注意到,您没有使用为其设置自定义LR的优化器,您可以尝试稍微降低LR,因为您当前正在使用Adam的默认设置


最后请注意,您还可以添加一个,这样可以保存最佳纪元的权重。

tensorflow的本教程提供了一个评估不同体系结构的好例子:

另一个非常重要的一点是学习率。在您的代码中,您使用了学习率为0.1的SGD,但最终您没有使用它。我建议像1e-3这样的低学习率。 此外,您还可以尝试以较低的历元数进行训练,如果模型仍在改进,您可以进一步训练

如果你很难找到一个好的学习率,这是一个很大的帮助:

您的val acc仍在增加,为什么不尝试更多的历险记,尝试一些类似提前停车的方法来监控停车标准