anderici
anderici

Reputation: 77

ValueError: Input 0 of layer conv3d_8 is incompatible with the layer: : expected min_ndim=5, found ndim=4. Full shape received: [None, 4, 150, 150]

I'm trying to train a 3D CNN model in Keras, but i'm getting this error when I execute the cell:

ValueError: Input 0 of layer conv3d_8 is incompatible with the layer: : expected min_ndim=5, found ndim=4. Full shape received: [None, 4, 150, 150]

My input data is a numpy array with image data. Here are the shapes (I know that 53 is too few, but it's just for studying purposes):

Training data shape:  (53, 4, 150, 150)
Training labels shape:  (53, 1)
Validation data shape:  (14, 4, 150, 150)
Validation labels shape:  (14, 1)

The model I'm trying to use is:

# Create the model
model = Sequential()
model.add(Conv3D(32, kernel_size=(3, 3, 3), activation='relu', kernel_initializer='he_uniform', input_shape=(4,150,150)))
model.add(MaxPooling3D(pool_size=(2, 2, 2)))
model.add(BatchNormalization(center=True, scale=True))
model.add(Dropout(0.5))
model.add(Conv3D(64, kernel_size=(3, 3, 3), activation='relu', kernel_initializer='he_uniform'))
model.add(MaxPooling3D(pool_size=(2, 2, 2)))
model.add(BatchNormalization(center=True, scale=True))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(256, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(256, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(4, activation='softmax'))

# Compile the model
model.compile(loss='categorical_crossentropy',
              optimizer=keras.optimizers.Adam(lr=0.001),
              metrics=['accuracy'])
model.summary()
# Fit data to model
history = model.fit(treino3d, treino3d_labels,
            epochs=40)

Can someone help, please?

Thanks a lot!

Upvotes: 1

Views: 2455

Answers (2)

Yuri Kreinin
Yuri Kreinin

Reputation: 158

  1. The first answer is correct. As I can recall (I didn't work with MRI for a couple of years), each slice is represented by 4 channels and each voxel in channel contains an information about the same physical position. Therefore, it would be correct approach to apply 2D-convolution for the image of 4 channels.
  2. For 2D convolution I would recommend to define your input with input_shape=(150,150,4), or even as input_shape=(None, None, 4) - it is more generic. So you don't need to play with channel_first or channel_last configuration. channel_last is default format, as I remember
  3. If you insist to use Conv3d, your input shape should be: input_shape=(150,150,4,1) or (None, None, None, 1) and trainset should follow shape like: np.random.rand(53, 150, 150, 4, 1)

Upvotes: 1

Nicolas Gervais
Nicolas Gervais

Reputation: 36584

It doesn't seem like you need Conv3D layers for this task. Use Conv2D instead, and use only 1 or 2 values in kernel_size and pool_size.

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', 
                 kernel_initializer='he_uniform', 
                 input_shape=(4,150,150)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization(center=True, scale=True))
model.add(Dropout(0.5))
model.add(Conv2D(64, kernel_size=(3, 3), activation='relu', 
                 kernel_initializer='he_uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization(center=True, scale=True))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(256, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(256, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(4, activation='softmax'))

Your channel dimension comes first so you will need to tell Keras. Use this line:

tf.keras.backend.set_image_data_format('channels_first')

Or set this parameter in every Conv2D or MaxPooling2D layer:

data_format='channels_first'

Or permute the dimensions of the input tensor to have shape (54, 150, 150, 4):

np.transpose(x, (0, 2, 3, 1))

Full functioning, corrected example:

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
from tensorflow.keras.layers import *
import numpy as np
from tensorflow.keras.models import Sequential

xtrain = np.random.rand(53, 4, 150, 150)
ytrain = np.random.randint(0, 4, (53, 1))

xtrain = np.transpose(xtrain, (0, 2, 3, 1))

model = Sequential()
model.add(Conv2D(8, kernel_size=(3, 3), activation='relu',
                 kernel_initializer='he_uniform', input_shape=xtrain.shape[1:]))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization(center=True, scale=True))
model.add(Dropout(0.5))
model.add(Conv2D(8, kernel_size=(3, 3), activation='relu',
          kernel_initializer='he_uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization(center=True, scale=True))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(32, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(32, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(4, activation='softmax'))

model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])
model.summary()

history = model.fit(xtrain, ytrain, epochs=1)
32/53 [=================>............] - ETA: 2s - loss: 1.8215 - acc: 0.2812
53/53 [==============================] - 5s 91ms/sample - loss: 1.9651 - acc: 0.2264

Upvotes: 2

Related Questions