I wrote a script to train a neural network to use .nii files as input, using the tutorial from TensorFlow here https://www.tensorflow.org/tutorials/load_data/images. I changed it slightly to work with NiBabel and .nii files but it still follows the same basic structure. However, I have encountered a problem where my loss converges to 0.6931, which I assume is because the model begins to guess the same thing regardless of the input, image shape or batch size. Thus, I believe the model is not learning. Can anyone identify any fatal flaws with my code; I’ve already tired:
- Callbacks with changing LR
- Changing the data, cleaning it, and reorganizing it
- Changing the proportions of the amount of each class
- Using different optimizers and loss functions
- Using a simple dense, dense, dense model but that does not seem to work as it does not even want to begin training
- Using a repeating dataset as well as a fixed size (Although it is unclear to me what difference that makes)
# Gets the label of the image, the label determines how tensorflow will classify the image
def get_label(file_path):
# Convert the path to a list of path components
parts = tf.strings.split(file_path, os.path.sep)
# The fourth last is the class-directory
return float(parts[-4] == "class1")
# Reads the data from a .nii file and returns a NumPy ndarray that is compatible with tensorflow
def decode_img(img):
img = nib.load(img.numpy().decode('utf-8'))
# convert the compressed string to a NumPy ndarray
data = img.get_fdata()
# Resize img
data = np.resize(data, imgshape)
# Normalize
max = np.amax(data)
min = np.amin(data)
data = ((data-min)/(max-min))
return data
# Processes a path to return a image data and label pair
def process_path(file_path):
# Gets the files label
label = get_label(file_path)
img = decode_img(file_path)
return img, label
I'm using these functions to process my data and mapping it over my list files datasets to process my data.
def configure_for_performance(ds):
#ds = ds.cache(filename='cachefile')
ds = ds.cache()
ds = ds.shuffle(buffer_size=1000)
ds = ds.repeat()
ds = ds.batch(BATCH_SIZE)
ds = ds.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
return ds
I pulled this directly from the TensorFlow tutorial.
# Create a sequential network
model = tf.keras.Sequential([
tf.keras.layers.Convolution3D(
4, 4, padding='same', data_format="channels_last", input_shape=imgshape, activation='tanh'),
tf.keras.layers.MaxPooling3D(padding='same'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Convolution3D(4, 4, padding='same', activation='tanh'),
tf.keras.layers.MaxPooling3D(padding='same'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Convolution3D(4, 4, padding='same', activation='tanh'),
tf.keras.layers.MaxPooling3D(padding='same'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Convolution3D(4, 4, padding='same', activation='tanh'),
tf.keras.layers.MaxPooling3D(padding='same'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(2048, activation='tanh'),
tf.keras.layers.Dense(1024, activation='tanh'),
tf.keras.layers.Dense(512, activation='tanh'),
tf.keras.layers.Dense(256, activation='tanh'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
model.summary()
model.fit(
train_ds,
validation_data=val_ds,
epochs=500,
steps_per_epoch=BATCH_SIZE,
validation_steps=BATCH_SIZE
)
This is my model, I'm using 3dconv similarly to how 2dconv is used in conventional image classification.
Any advice would be appreciated!