我正在尝试创建一个CNN,对3D大脑图像进行分类。 然而,CNN程序总是在我运行它时预测相同的类,并且不确定我还能做什么其他方法来防止这一点。 我用许多看似合理的解决办法来寻找这个问题,但都不起作用
到目前为止,我已经尝试:
请注意,我使用的图像数量是总共20个3D大脑图像(每类5个),我不能增加样本量,因为根本没有足够的图像。 我最近尝试了数据增强,但是这似乎没有帮助。
如有任何帮助,我们将不胜感激!
import os
import csv
import tensorflow as tf # 2.0
import nibabel as nib
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from keras.models import Model
from keras.layers import Conv3D, MaxPooling3D, Dense, Dropout, Activation, Flatten
from keras.layers import Input, concatenate
from keras import optimizers
from keras.utils import to_categorical
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
from augmentedvolumetricimagegenerator.generator import customImageDataGenerator
from keras.callbacks import EarlyStopping
# Administrative items
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# Where the file is located
path = r'C:\Users\jesse\OneDrive\Desktop\Research\PD\decline2'
folder = os.listdir(path)
target_size = (96, 96, 96)
# creating x - converting images to array
def read_image(path, folder):
mri = []
for i in range(len(folder)):
files = os.listdir(path + '\\' + folder[i])
for j in range(len(files)):
image = np.array(nib.load(path + '\\' + folder[i] + '\\' + files[j]).get_fdata())
image = np.resize(image, target_size)
image = np.expand_dims(image, axis=3)
mri.append(image)
return mri
# creating y - one hot encoder
def create_y():
excel_file = r'C:\Users\jesse\OneDrive\Desktop\Research\PD\decline_label.xlsx'
excel_read = pd.read_excel(excel_file)
excel_array = np.array(excel_read['Label'])
label = LabelEncoder().fit_transform(excel_array)
label = label.reshape(len(label), 1)
onehot = OneHotEncoder(sparse=False).fit_transform(label)
return onehot
# Splitting image train/test
x = np.asarray(read_image(path, folder))
y = np.asarray(create_y())
test_size = .2
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=test_size)
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
batch_size = 4
num_classes = 4
inputs = Input((96, 96, 96, 1))
conv1 = Conv3D(32, [3, 3, 3], padding='same', activation='relu')(inputs)
conv1 = Conv3D(32, [3, 3, 3], padding='same', activation='relu')(conv1)
pool1 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv1)
drop1 = Dropout(0.5)(pool1)
conv2 = Conv3D(64, [3, 3, 3], padding='same', activation='relu')(drop1)
conv2 = Conv3D(64, [3, 3, 3], padding='same', activation='relu')(conv2)
pool2 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv2)
drop2 = Dropout(0.5)(pool2)
conv3 = Conv3D(128, [3, 3, 3], padding='same', activation='relu')(drop2)
conv3 = Conv3D(128, [3, 3, 3], padding='same', activation='relu')(conv3)
pool3 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv3)
drop3 = Dropout(0.5)(pool3)
conv4 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(drop3)
conv4 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(conv4)
pool4 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv4)
drop4 = Dropout(0.5)(pool4)
conv5 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(drop4)
conv5 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(conv5)
pool5 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv5)
drop5 = Dropout(0.5)(pool5)
flat1 = Flatten()(drop5)
dense1 = Dense(128, activation='relu')(flat1)
dense2 = Dense(64, activation='relu')(dense1)
dense3 = Dense(32, activation='relu')(dense2)
drop6 = Dropout(0.5)(dense3)
dense4 = Dense(num_classes, activation='softmax')(drop6)
model = Model(inputs=[inputs], outputs=[dense4])
opt = optimizers.Adam(lr=1e-8, beta_1=1e-3, beta_2=1e-4, decay=2e-5)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
train_datagen = customImageDataGenerator(rescale=1./255,
#width_shift_range=0.2,
#height_shift_range=0.2,
#rotation_range=15,
#shear_range=0.2,
#zoom_range=0.2,
#brightness_range=[0.2, 1.0],
data_format='channels_last',
horizontal_flip=True)
test_datagen = customImageDataGenerator(rescale=1./255)
training_set = train_datagen.flow(x_train, y_train, batch_size=batch_size)
testing_set = test_datagen.flow(x_test, y_test, batch_size=batch_size)
callbacks = EarlyStopping(monitor='val_loss')
model.fit_generator(training_set,
steps_per_epoch = 20,
epochs = 30,
validation_steps = 5,
callbacks = [callbacks],
validation_data = testing_set)
#score = model.evaluate(x_test, y_test, batch_size=batch_size)
#print(score)
y_pred = model.predict(x_test, batch_size=batch_size)
y_test = np.argmax(y_test, axis=1)
y_pred = np.argmax(y_pred, axis=1)
confusion = confusion_matrix(y_test, y_pred)
map = sns.heatmap(confusion, annot=True)
print(map)
不知道到底发生了什么。 但我有几点意见和建议。
首先看一下学习曲线,看看它是否真的符合一些东西。
其次,您将0.2%的数据集用于由5个类的20幅图像组成的数据集。 如果所有最后的图像都是同一个标签。 你只会在那个标签上测试。 所以这可能是这里的一个问题,除非图像没有被分类。
第三,对于为数不多的数据,看起来您可能有很多密集的参数。 通常从小处开始,增加参数的数量。 通过观察学习曲线,你可以看到一些关于这一点的提示。
最后,可悲的是,机器学习并不神奇,你不能指望用那么少的数据取得好的结果。
阿莱克斯