I am getting the following error when I am trying to run a 1D CNN on a 7 band spectral data. The class labels are binary, and I want a single output. I am attaching the code and the outputs. Apparently, it seems that Conv1D is having some problems ingesting the 7 input bands. I have tried looking at the posts that are already out there, but without much success.
import numpy as np
import rasterio
from rasterio.plot import show
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from tensorflow import keras
from sklearn.metrics import confusion_matrix, precision_score, recall_score
from tensorflow.keras.utils import plot_model
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import Dense, Conv1D, MaxPooling1D
from tensorflow.keras.layers import Concatenate
from spectral import *
import pysptools.spectro as spectro
import copy
import os
import matplotlib
from sklearn.preprocessing import OneHotEncoder
import pandas as pd
import shutil
#%% DEFINE THE 1D CNN MODEL ARCHITECTURE
filters=4
kernel_size=4
visible = Input(shape=(7,1))
hidden1 = Conv1D (filters=filters, kernel_size=kernel_size, input_shape=(7,1), activation='relu', name="L1")(visible)
hidden2 = MaxPooling1D()(hidden1)
hidden3 = Dense(2, activation='relu', name="L3")(hidden2)
# hidden4 = Dense(2, activation='relu', name="L4")(hidden3)
output = Dense(1, activation='softmax', name="Output")(hidden3)
model = Model(inputs=visible, outputs=output)
# Shapes of the input data and label
print("\n7 band spectral data shape:", ern_T_c_d_v.shape)
print("Class labels shape:", ern_Mask_c_d_v.shape)
# Split into test and train
xTrain, xTest, yTrain, yTest = train_test_split(ern_T_c_d_v, ern_Mask_c_d_v, test_size=0.5, random_state=42)
# Note that I have transposed the arrays...
print("\nBefore reshaping")
print("xTrain:", xTrain.shape)
print("yTrain", yTrain.shape)
print("xTest:",xTest.shape)
print("yTest:",yTest.shape)
xTrain = np.reshape(xTrain, (xTrain.shape[0], 1, xTrain.shape[1]))
xTest = np.reshape(xTest, (xTest.shape[0], 1, xTest.shape[1]))
# xTrain=np.expand_dims(xTrain, axis=1)
# xTest=np.expand_dims(xTrain, axis=1)
print("\nReshaped...")
print("xTrain:", xTrain.shape)
print("yTrain:", yTrain.shape)
print("xTest:", xTest.shape)
print("yTest:",yTest.shape)
#%%
# Define the accuracy metrics and parameters
# opt=keras.optimizers.Adam(learning_rate=0.001)
model.compile(optimizer='adam', loss="binary_crossentropy", metrics=["accuracy"])
# Run the model
history = model.fit(xTrain, yTrain, epochs=1500)
pd.DataFrame(history.history).plot(figsize=(6,4))
plt.savefig(path os.sep 'History')
plt.show()
print(history.params)
#%%
# Predict for test data
yTestPredicted = model.predict(xTest)
AND, this is what I get:
Warning 1: TIFFReadDirectoryCheckOrder:Invalid TIFF directory; tags are not sorted in ascending order
Warning 1: TIFFReadDirectory:Sum of Photometric type-related color channels and ExtraSamples doesn't match SamplesPerPixel. Defining non-color channels as ExtraSamples.
Model: "model_15"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_19 (InputLayer) [(None, 7, 1)] 0
_________________________________________________________________
L1 (Conv1D) (None, 4, 6) 30
_________________________________________________________________
max_pooling1d_15 (MaxPooling (None, 2, 6) 0
_________________________________________________________________
L3 (Dense) (None, 2, 4) 28
_________________________________________________________________
Output (Dense) (None, 2, 1) 5
=================================================================
Total params: 63
Trainable params: 63
Non-trainable params: 0
_________________________________________________________________
None
7 band spectral data shape: (1201, 7)
Class labels shape: (1201,)
Before reshaping
xTrain: (600, 7)
yTrain (600,)
xTest: (601, 7)
yTest: (601,)
Reshaped...
xTrain: (600, 1, 7)
yTrain: (600,)
xTest: (601, 1, 7)
yTest: (601,)
Traceback (most recent call last):
File "/Volumes/256GB/Ceres_Red_FC/NN_Codes/NN_Functional_CNN_1.py", line 181, in <module>
history = model.fit(xTrain, yTrain, epochs=1500)
File "/Users/pragya/opt/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training.py", line 728, in fit
use_multiprocessing=use_multiprocessing)
File "/Users/pragya/opt/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training_v2.py", line 224, in fit
distribution_strategy=strategy)
File "/Users/pragya/opt/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training_v2.py", line 547, in _process_training_inputs
use_multiprocessing=use_multiprocessing)
File "/Users/pragya/opt/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training_v2.py", line 594, in _process_inputs
steps=steps)
File "/Users/pragya/opt/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training.py", line 2472, in _standardize_user_data
exception_prefix='input')
File "/Users/pragya/opt/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training_utils.py", line 574, in standardize_input_data
str(data_shape))
ValueError: Error when checking input: expected input_19 to have shape (7, 1) but got array with shape (1, 7)
I am not able to understand why Conv1D can't accept the 7 input bands. Any ideas how to get around this? Thanks in advance...
CodePudding user response:
The following is working for me
from tensorflow.keras.utils import plot_model
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import Dense, Conv1D, MaxPooling1D
from tensorflow.keras.layers import Concatenate
import numpy as np
nexamples = 200
filters=4
kernel_size=4
xTrain = np.zeros((nexamples,7,1),dtype='float64')
yTrain = np.zeros((nexamples,),dtype='float64')
visible = Input(shape=(7,1))
hidden1 = Conv1D(filters=filters, kernel_size=kernel_size, input_shape=(7,1), activation='relu', name="L1")(visible)
hidden2 = MaxPooling1D()(hidden1)
hidden3 = Dense(2, activation='relu', name="L3")(hidden2)
# hidden4 = Dense(2, activation='relu', name="L4")(hidden3)
output = Dense(1, activation='softmax', name="Output")(hidden3)
model = Model(inputs=visible, outputs=output)
model.compile(optimizer='adam', loss="binary_crossentropy", metrics=["accuracy"])
# Run the model
history = model.fit(xTrain, yTrain, epochs=1)
CodePudding user response:
If you change this line
xTrain = np.reshape(xTrain, (xTrain.shape[0], 1, xTrain.shape[1]))
xTest = np.reshape(xTest, (xTest.shape[0], 1, xTest.shape[1]))
To this
xTrain = np.reshape(xTrain, (xTrain.shape[0], xTrain.shape[1], 1))
xTest = np.reshape(xTest, (xTest.shape[0], xTest.shape[1], 1))
the fit function works. To better understand this you need to know that the convolutions have a channel in the shape, you are given a 7 channel example with only one value and you are trying to pass a 4 size kernel to this single input, They are two ways to solve this you can create an input with 7 values and only 1 channel as the example above or you can do a separable convolution between the channels.