繁体   English   中英

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

[英]CNN for image classification performing poorly

我正在构建一个用于膝关节 X 射线图像处理的 CNN,但是在每次运行的第 7-8 个 Epoch 之后,验证和训练损失/准确性不对齐,一段时间后验证损失开始增加。 我尝试通过数据增强来增加我的数据集。 现在我想知道是否可能是图像的质量、我的实际架构或我保存数据的方式。 对于我的数据预处理,我将每个图像保存为一个 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
  • 尝试在卷积之间添加 dropout(我会使用 SpatialDropout2D)

此外,我注意到您没有使用为其设置自定义 LR 的优化器,您可以尝试稍微降低 LR,因为您当前使用的是 Adam 的默认设置。

最后要注意的是,您还可以为提前停止添加回调,以便保存最佳时期的权重。

来自 tensorflow 的这个教程提供了一个评估不同架构的好例子:https ://www.tensorflow.org/tutorials/keras/overfit_and_underfit

另一个非常重要的一点是学习率。 在您的代码中,您使用学习率=0.1 的 SGD,但最终您没有使用它。 我建议使用较低的学习率,例如 1e-3。 您也可以尝试以低 epoch 进行训练,如果模型仍在改进,您可以进一步训练。

如果你很难找到一个好的学习率,这是一个很大的帮助: https : //gist.github.com/WittmannF/c55ed82d27248d18799e2be324a79473

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM